mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ASoC: samsung: remove unused drivers
The s3c24xx SoC platform was completely removed, as were most of the s3c64xx based board files, leaving only the DT based machines as well as the MACH_WLF_CRAGG_6410 machine. All other board specific ASoC driver can can now be recycled. Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
		
							parent
							
								
									2e3ee090cd
								
							
						
					
					
						commit
						503278c127
					
				
					 23 changed files with 0 additions and 4151 deletions
				
			
		| 
						 | 
				
			
			@ -1,30 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0-only */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2008 Simtec Electronics
 | 
			
		||||
 *	http://armlinux.simtec.co.uk/
 | 
			
		||||
 *	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 *
 | 
			
		||||
 * Simtec Audio support.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct s3c24xx_audio_simtec_pdata - platform data for simtec audio
 | 
			
		||||
 * @use_mpllin: Select codec clock from MPLLin
 | 
			
		||||
 * @output_cdclk: Need to output CDCLK to the codec
 | 
			
		||||
 * @have_mic: Set if we have a MIC socket
 | 
			
		||||
 * @have_lout: Set if we have a LineOut socket
 | 
			
		||||
 * @amp_gpio: GPIO pin to enable the AMP
 | 
			
		||||
 * @amp_gain: Option GPIO to control AMP gain
 | 
			
		||||
 */
 | 
			
		||||
struct s3c24xx_audio_simtec_pdata {
 | 
			
		||||
	unsigned int	use_mpllin:1;
 | 
			
		||||
	unsigned int	output_cdclk:1;
 | 
			
		||||
 | 
			
		||||
	unsigned int	have_mic:1;
 | 
			
		||||
	unsigned int	have_lout:1;
 | 
			
		||||
 | 
			
		||||
	int		amp_gpio;
 | 
			
		||||
	int		amp_gain[2];
 | 
			
		||||
 | 
			
		||||
	void	(*startup)(void);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
#ifndef _S3C24XX_UDA134X_H_
 | 
			
		||||
#define _S3C24XX_UDA134X_H_ 1
 | 
			
		||||
 | 
			
		||||
#include <sound/uda134x.h>
 | 
			
		||||
 | 
			
		||||
struct s3c24xx_uda134x_platform_data {
 | 
			
		||||
	int l3_clk;
 | 
			
		||||
	int l3_mode;
 | 
			
		||||
	int l3_data;
 | 
			
		||||
	int model;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -11,16 +11,6 @@ menuconfig SND_SOC_SAMSUNG
 | 
			
		|||
 | 
			
		||||
if SND_SOC_SAMSUNG
 | 
			
		||||
 | 
			
		||||
config SND_S3C24XX_I2S
 | 
			
		||||
	tristate
 | 
			
		||||
 | 
			
		||||
config SND_S3C_I2SV2_SOC
 | 
			
		||||
	tristate
 | 
			
		||||
 | 
			
		||||
config SND_S3C2412_SOC_I2S
 | 
			
		||||
	tristate
 | 
			
		||||
	select SND_S3C_I2SV2_SOC
 | 
			
		||||
 | 
			
		||||
config SND_SAMSUNG_PCM
 | 
			
		||||
	tristate "Samsung PCM interface support"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,35 +21,6 @@ config SND_SAMSUNG_SPDIF
 | 
			
		|||
config SND_SAMSUNG_I2S
 | 
			
		||||
	tristate "Samsung I2S interface support"
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_NEO1973_WM8753
 | 
			
		||||
	tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
 | 
			
		||||
	depends on MACH_NEO1973_GTA02 || COMPILE_TEST
 | 
			
		||||
	depends on SND_SOC_I2C_AND_SPI
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_WM8753
 | 
			
		||||
	select SND_SOC_BT_SCO
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to enable audio support for the Openmoko Neo1973
 | 
			
		||||
	  Smartphones.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_JIVE_WM8750
 | 
			
		||||
	tristate "SoC I2S Audio support for Jive"
 | 
			
		||||
	depends on MACH_JIVE && I2C || COMPILE_TEST && ARM
 | 
			
		||||
	depends on SND_SOC_I2C_AND_SPI
 | 
			
		||||
	select SND_SOC_WM8750
 | 
			
		||||
	select SND_S3C2412_SOC_I2S
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y if you want to add support for SoC audio on the Jive.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SMDK_WM8580
 | 
			
		||||
	tristate "SoC I2S Audio support for WM8580 on SMDK"
 | 
			
		||||
	depends on MACH_SMDK6410 || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_SOC_WM8580
 | 
			
		||||
	select SND_SAMSUNG_I2S
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y if you want to add support for SoC audio on the SMDKs.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SMDK_WM8994
 | 
			
		||||
	tristate "SoC I2S Audio support for WM8994 on SMDK"
 | 
			
		||||
	depends on I2C=y
 | 
			
		||||
| 
						 | 
				
			
			@ -69,60 +30,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
 | 
			
		|||
	help
 | 
			
		||||
		Say Y if you want to add support for SoC audio on the SMDKs.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_S3C24XX_UDA134X
 | 
			
		||||
	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
 | 
			
		||||
	depends on ARCH_S3C24XX || COMPILE_TEST
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_L3
 | 
			
		||||
	select SND_SOC_UDA134X
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SIMTEC
 | 
			
		||||
	tristate
 | 
			
		||||
	help
 | 
			
		||||
	  Internal node for common S3C24XX/Simtec support.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
 | 
			
		||||
	tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
 | 
			
		||||
	depends on ARCH_S3C24XX || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_TLV320AIC23_I2C
 | 
			
		||||
	select SND_SOC_SAMSUNG_SIMTEC
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SIMTEC_HERMES
 | 
			
		||||
	tristate "SoC I2S Audio support for Simtec Hermes board"
 | 
			
		||||
	depends on ARCH_S3C24XX || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_TLV320AIC3X
 | 
			
		||||
	select SND_SOC_SAMSUNG_SIMTEC
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_H1940_UDA1380
 | 
			
		||||
	tristate "Audio support for the HP iPAQ H1940"
 | 
			
		||||
	depends on ARCH_H1940 || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_UDA1380
 | 
			
		||||
	help
 | 
			
		||||
	  This driver provides audio support for HP iPAQ h1940 PDA.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_RX1950_UDA1380
 | 
			
		||||
	tristate "Audio support for the HP iPAQ RX1950"
 | 
			
		||||
	depends on MACH_RX1950 || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_S3C24XX_I2S
 | 
			
		||||
	select SND_SOC_UDA1380
 | 
			
		||||
	help
 | 
			
		||||
	  This driver provides audio support for HP iPAQ RX1950 PDA.
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SMARTQ
 | 
			
		||||
	tristate "SoC I2S Audio support for SmartQ board"
 | 
			
		||||
	depends on MACH_SMARTQ || COMPILE_TEST
 | 
			
		||||
	depends on GPIOLIB || COMPILE_TEST
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	select SND_SAMSUNG_I2S
 | 
			
		||||
	select SND_SOC_WM8750
 | 
			
		||||
 | 
			
		||||
config SND_SOC_SAMSUNG_SMDK_SPDIF
 | 
			
		||||
	tristate "SoC S/PDIF Audio support for SMDK"
 | 
			
		||||
	select SND_SAMSUNG_SPDIF
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,35 +2,19 @@
 | 
			
		|||
# S3c24XX Platform Support
 | 
			
		||||
snd-soc-s3c-dma-objs := dmaengine.o
 | 
			
		||||
snd-soc-idma-objs := idma.o
 | 
			
		||||
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 | 
			
		||||
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 | 
			
		||||
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
 | 
			
		||||
snd-soc-samsung-spdif-objs := spdif.o
 | 
			
		||||
snd-soc-pcm-objs := pcm.o
 | 
			
		||||
snd-soc-i2s-objs := i2s.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o
 | 
			
		||||
obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
 | 
			
		||||
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
 | 
			
		||||
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
 | 
			
		||||
obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
 | 
			
		||||
obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
 | 
			
		||||
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
 | 
			
		||||
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
 | 
			
		||||
 | 
			
		||||
# S3C24XX Machine Support
 | 
			
		||||
snd-soc-jive-wm8750-objs := jive_wm8750.o
 | 
			
		||||
snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
 | 
			
		||||
snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 | 
			
		||||
snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
 | 
			
		||||
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
 | 
			
		||||
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
 | 
			
		||||
snd-soc-h1940-uda1380-objs := h1940_uda1380.o
 | 
			
		||||
snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
 | 
			
		||||
snd-soc-smdk-wm8580-objs := smdk_wm8580.o
 | 
			
		||||
snd-soc-smdk-wm8994-objs := smdk_wm8994.o
 | 
			
		||||
snd-soc-snow-objs := snow.o
 | 
			
		||||
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 | 
			
		||||
snd-soc-smdk-spdif-objs := smdk_spdif.o
 | 
			
		||||
snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
 | 
			
		||||
snd-soc-speyside-objs := speyside.o
 | 
			
		||||
| 
						 | 
				
			
			@ -44,18 +28,8 @@ snd-soc-tm2-wm5110-objs := tm2_wm5110.o
 | 
			
		|||
snd-soc-aries-wm8994-objs := aries_wm8994.o
 | 
			
		||||
snd-soc-midas-wm1811-objs := midas_wm1811.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
 | 
			
		||||
obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,224 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// h1940_uda1380.c - ALSA SoC Audio Layer
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
 | 
			
		||||
// Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
 | 
			
		||||
//
 | 
			
		||||
// Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/gpio/consumer.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/jack.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-iis.h"
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
 | 
			
		||||
static const unsigned int rates[] = {
 | 
			
		||||
	11025,
 | 
			
		||||
	22050,
 | 
			
		||||
	44100,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_pcm_hw_constraint_list hw_rates = {
 | 
			
		||||
	.count = ARRAY_SIZE(rates),
 | 
			
		||||
	.list = rates,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct gpio_desc *gpiod_speaker_power;
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack hp_jack;
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_pin hp_jack_pins[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.pin	= "Headphone Jack",
 | 
			
		||||
		.mask	= SND_JACK_HEADPHONE,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.pin	= "Speaker",
 | 
			
		||||
		.mask	= SND_JACK_HEADPHONE,
 | 
			
		||||
		.invert	= 1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_gpio hp_jack_gpios[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name			= "hp-gpio",
 | 
			
		||||
		.report			= SND_JACK_HEADPHONE,
 | 
			
		||||
		.invert			= 1,
 | 
			
		||||
		.debounce_time		= 200,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int h1940_startup(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_pcm_runtime *runtime = substream->runtime;
 | 
			
		||||
 | 
			
		||||
	return snd_pcm_hw_constraint_list(runtime, 0,
 | 
			
		||||
					SNDRV_PCM_HW_PARAM_RATE,
 | 
			
		||||
					&hw_rates);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int h1940_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	int div;
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned int rate = params_rate(params);
 | 
			
		||||
 | 
			
		||||
	switch (rate) {
 | 
			
		||||
	case 11025:
 | 
			
		||||
	case 22050:
 | 
			
		||||
	case 44100:
 | 
			
		||||
		div = s3c24xx_i2s_get_clockrate() / (384 * rate);
 | 
			
		||||
		if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate))
 | 
			
		||||
			div++;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		dev_err(rtd->dev, "%s: rate %d is not supported\n",
 | 
			
		||||
			__func__, rate);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* select clock source */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
 | 
			
		||||
			SND_SOC_CLOCK_OUT);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set MCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
 | 
			
		||||
		S3C2410_IISMOD_384FS);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set BCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
 | 
			
		||||
		S3C2410_IISMOD_32FS);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set prescaler division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 | 
			
		||||
		S3C24XX_PRESCALE(div, div));
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops h1940_ops = {
 | 
			
		||||
	.startup	= h1940_startup,
 | 
			
		||||
	.hw_params	= h1940_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int h1940_spk_power(struct snd_soc_dapm_widget *w,
 | 
			
		||||
				struct snd_kcontrol *kcontrol, int event)
 | 
			
		||||
{
 | 
			
		||||
	if (SND_SOC_DAPM_EVENT_ON(event))
 | 
			
		||||
		gpiod_set_value(gpiod_speaker_power, 1);
 | 
			
		||||
	else
 | 
			
		||||
		gpiod_set_value(gpiod_speaker_power, 0);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* h1940 machine dapm widgets */
 | 
			
		||||
static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_SPK("Speaker", h1940_spk_power),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* h1940 machine audio_map */
 | 
			
		||||
static const struct snd_soc_dapm_route audio_map[] = {
 | 
			
		||||
	/* headphone connected to VOUTLHP, VOUTRHP */
 | 
			
		||||
	{"Headphone Jack", NULL, "VOUTLHP"},
 | 
			
		||||
	{"Headphone Jack", NULL, "VOUTRHP"},
 | 
			
		||||
 | 
			
		||||
	/* ext speaker connected to VOUTL, VOUTR  */
 | 
			
		||||
	{"Speaker", NULL, "VOUTL"},
 | 
			
		||||
	{"Speaker", NULL, "VOUTR"},
 | 
			
		||||
 | 
			
		||||
	/* mic is connected to VINM */
 | 
			
		||||
	{"VINM", NULL, "Mic Jack"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
 | 
			
		||||
		SND_JACK_HEADPHONE,
 | 
			
		||||
		&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 | 
			
		||||
 | 
			
		||||
	snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
 | 
			
		||||
		hp_jack_gpios);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* s3c24xx digital audio interface glue - connects codec <--> CPU */
 | 
			
		||||
SND_SOC_DAILINK_DEFS(uda1380,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-001a", "uda1380-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link h1940_uda1380_dai[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name		= "uda1380",
 | 
			
		||||
		.stream_name	= "UDA1380 Duplex",
 | 
			
		||||
		.init		= h1940_uda1380_init,
 | 
			
		||||
		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
				  SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
		.ops		= &h1940_ops,
 | 
			
		||||
		SND_SOC_DAILINK_REG(uda1380),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card h1940_asoc = {
 | 
			
		||||
	.name = "h1940",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = h1940_uda1380_dai,
 | 
			
		||||
	.num_links = ARRAY_SIZE(h1940_uda1380_dai),
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets = uda1380_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
 | 
			
		||||
	.dapm_routes = audio_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(audio_map),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int h1940_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
 | 
			
		||||
	h1940_asoc.dev = dev;
 | 
			
		||||
	hp_jack_gpios[0].gpiod_dev = dev;
 | 
			
		||||
	gpiod_speaker_power = devm_gpiod_get(&pdev->dev, "speaker-power",
 | 
			
		||||
					     GPIOD_OUT_LOW);
 | 
			
		||||
 | 
			
		||||
	if (IS_ERR(gpiod_speaker_power)) {
 | 
			
		||||
		dev_err(dev, "Could not get gpio\n");
 | 
			
		||||
		return PTR_ERR(gpiod_speaker_power);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return devm_snd_soc_register_card(dev, &h1940_asoc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver h1940_audio_driver = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "h1940-audio",
 | 
			
		||||
		.pm = &snd_soc_pm_ops,
 | 
			
		||||
	},
 | 
			
		||||
	.probe = h1940_probe,
 | 
			
		||||
};
 | 
			
		||||
module_platform_driver(h1940_audio_driver);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC H1940");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("platform:h1940-audio");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,143 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2007,2008 Simtec Electronics
 | 
			
		||||
//
 | 
			
		||||
// Based on sound/soc/pxa/spitz.c
 | 
			
		||||
//	Copyright 2005 Wolfson Microelectronics PLC.
 | 
			
		||||
//	Copyright 2005 Openedhand Ltd.
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-types.h>
 | 
			
		||||
 | 
			
		||||
#include "s3c2412-i2s.h"
 | 
			
		||||
#include "../codecs/wm8750.h"
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_route audio_map[] = {
 | 
			
		||||
	{ "Headphone Jack", NULL, "LOUT1" },
 | 
			
		||||
	{ "Headphone Jack", NULL, "ROUT1" },
 | 
			
		||||
	{ "Internal Speaker", NULL, "LOUT2" },
 | 
			
		||||
	{ "Internal Speaker", NULL, "ROUT2" },
 | 
			
		||||
	{ "LINPUT1", NULL, "Line Input" },
 | 
			
		||||
	{ "RINPUT1", NULL, "Line Input" },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_SPK("Internal Speaker", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("Line In", NULL),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int jive_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
			  struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	struct s3c_i2sv2_rate_calc div;
 | 
			
		||||
	unsigned int clk = 0;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	switch (params_rate(params)) {
 | 
			
		||||
	case 8000:
 | 
			
		||||
	case 16000:
 | 
			
		||||
	case 48000:
 | 
			
		||||
	case 96000:
 | 
			
		||||
		clk = 12288000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 11025:
 | 
			
		||||
	case 22050:
 | 
			
		||||
	case 44100:
 | 
			
		||||
		clk = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
 | 
			
		||||
				s3c_i2sv2_get_clock(cpu_dai));
 | 
			
		||||
 | 
			
		||||
	/* set the codec system clock for DAC and ADC */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
 | 
			
		||||
				     SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
 | 
			
		||||
				     div.clk_div - 1);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops jive_ops = {
 | 
			
		||||
	.hw_params	= jive_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(wm8750,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c2412-i2s")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001a", "wm8750-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c2412-i2s")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link jive_dai = {
 | 
			
		||||
	.name		= "wm8750",
 | 
			
		||||
	.stream_name	= "WM8750",
 | 
			
		||||
	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
			  SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
	.ops		= &jive_ops,
 | 
			
		||||
	SND_SOC_DAILINK_REG(wm8750),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* jive audio machine driver */
 | 
			
		||||
static struct snd_soc_card snd_soc_machine_jive = {
 | 
			
		||||
	.name		= "Jive",
 | 
			
		||||
	.owner		= THIS_MODULE,
 | 
			
		||||
	.dai_link	= &jive_dai,
 | 
			
		||||
	.num_links	= 1,
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets	= wm8750_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
 | 
			
		||||
	.dapm_routes	= audio_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(audio_map),
 | 
			
		||||
	.fully_routed	= true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device *jive_snd_device;
 | 
			
		||||
 | 
			
		||||
static int __init jive_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!machine_is_jive())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	printk("JIVE WM8750 Audio support\n");
 | 
			
		||||
 | 
			
		||||
	jive_snd_device = platform_device_alloc("soc-audio", -1);
 | 
			
		||||
	if (!jive_snd_device)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
 | 
			
		||||
	ret = platform_device_add(jive_snd_device);
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		platform_device_put(jive_snd_device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit jive_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_device_unregister(jive_snd_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(jive_init);
 | 
			
		||||
module_exit(jive_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,360 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// neo1973_wm8753.c - SoC audio for Openmoko Neo1973 and Freerunner devices
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2007 Openmoko Inc
 | 
			
		||||
// Author: Graeme Gregory <graeme@openmoko.org>
 | 
			
		||||
// Copyright 2007 Wolfson Microelectronics PLC.
 | 
			
		||||
// Author: Graeme Gregory
 | 
			
		||||
//         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
 | 
			
		||||
// Copyright 2009 Wolfson Microelectronics
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/gpio/consumer.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-iis.h"
 | 
			
		||||
#include "../codecs/wm8753.h"
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
 | 
			
		||||
static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
	struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	unsigned int pll_out = 0, bclk = 0;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	unsigned long iis_clkrate;
 | 
			
		||||
 | 
			
		||||
	iis_clkrate = s3c24xx_i2s_get_clockrate();
 | 
			
		||||
 | 
			
		||||
	switch (params_rate(params)) {
 | 
			
		||||
	case 8000:
 | 
			
		||||
	case 16000:
 | 
			
		||||
		pll_out = 12288000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 48000:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_4;
 | 
			
		||||
		pll_out = 12288000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 96000:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_2;
 | 
			
		||||
		pll_out = 12288000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 11025:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_16;
 | 
			
		||||
		pll_out = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	case 22050:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_8;
 | 
			
		||||
		pll_out = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	case 44100:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_4;
 | 
			
		||||
		pll_out = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	case 88200:
 | 
			
		||||
		bclk = WM8753_BCLK_DIV_2;
 | 
			
		||||
		pll_out = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* set the codec system clock for DAC and ADC */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
 | 
			
		||||
		SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set MCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
 | 
			
		||||
		S3C2410_IISMOD_32FS);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set codec BCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set prescaler division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 | 
			
		||||
		S3C24XX_PRESCALE(4, 4));
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* codec PLL input is PCLK/4 */
 | 
			
		||||
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
 | 
			
		||||
		iis_clkrate / 4, pll_out);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
 | 
			
		||||
	/* disable the PLL */
 | 
			
		||||
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Neo1973 WM8753 HiFi DAI opserations.
 | 
			
		||||
 */
 | 
			
		||||
static const struct snd_soc_ops neo1973_hifi_ops = {
 | 
			
		||||
	.hw_params = neo1973_hifi_hw_params,
 | 
			
		||||
	.hw_free = neo1973_hifi_hw_free,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
	struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	unsigned int pcmdiv = 0;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	unsigned long iis_clkrate;
 | 
			
		||||
 | 
			
		||||
	iis_clkrate = s3c24xx_i2s_get_clockrate();
 | 
			
		||||
 | 
			
		||||
	if (params_rate(params) != 8000)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (params_channels(params) != 1)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
 | 
			
		||||
 | 
			
		||||
	/* set the codec system clock for DAC and ADC */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
 | 
			
		||||
		SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set codec PCM division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* configure and enable PLL for 12.288MHz output */
 | 
			
		||||
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
 | 
			
		||||
		iis_clkrate / 4, 12288000);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
 | 
			
		||||
	/* disable the PLL */
 | 
			
		||||
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops neo1973_voice_ops = {
 | 
			
		||||
	.hw_params = neo1973_voice_hw_params,
 | 
			
		||||
	.hw_free = neo1973_voice_hw_free,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct gpio_desc *gpiod_hp_in, *gpiod_amp_shut;
 | 
			
		||||
static int gta02_speaker_enabled;
 | 
			
		||||
 | 
			
		||||
static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
 | 
			
		||||
	struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	gta02_speaker_enabled = ucontrol->value.integer.value[0];
 | 
			
		||||
 | 
			
		||||
	gpiod_set_value(gpiod_hp_in, !gta02_speaker_enabled);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
 | 
			
		||||
	struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	ucontrol->value.integer.value[0] = gta02_speaker_enabled;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lm4853_event(struct snd_soc_dapm_widget *w,
 | 
			
		||||
			struct snd_kcontrol *k, int event)
 | 
			
		||||
{
 | 
			
		||||
	gpiod_set_value(gpiod_amp_shut, SND_SOC_DAPM_EVENT_OFF(event));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_LINE("GSM Line Out", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("GSM Line In", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 | 
			
		||||
	SND_SOC_DAPM_SPK("Handset Spk", NULL),
 | 
			
		||||
	SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
 | 
			
		||||
	/* Connections to the GSM Module */
 | 
			
		||||
	{"GSM Line Out", NULL, "MONO1"},
 | 
			
		||||
	{"GSM Line Out", NULL, "MONO2"},
 | 
			
		||||
	{"RXP", NULL, "GSM Line In"},
 | 
			
		||||
	{"RXN", NULL, "GSM Line In"},
 | 
			
		||||
 | 
			
		||||
	/* Connections to Headset */
 | 
			
		||||
	{"MIC1", NULL, "Mic Bias"},
 | 
			
		||||
	{"Mic Bias", NULL, "Headset Mic"},
 | 
			
		||||
 | 
			
		||||
	/* Call Mic */
 | 
			
		||||
	{"MIC2", NULL, "Mic Bias"},
 | 
			
		||||
	{"MIC2N", NULL, "Mic Bias"},
 | 
			
		||||
	{"Mic Bias", NULL, "Handset Mic"},
 | 
			
		||||
 | 
			
		||||
	/* Connect the ALC pins */
 | 
			
		||||
	{"ACIN", NULL, "ACOP"},
 | 
			
		||||
 | 
			
		||||
	/* Connections to the amp */
 | 
			
		||||
	{"Stereo Out", NULL, "LOUT1"},
 | 
			
		||||
	{"Stereo Out", NULL, "ROUT1"},
 | 
			
		||||
 | 
			
		||||
	/* Call Speaker */
 | 
			
		||||
	{"Handset Spk", NULL, "LOUT2"},
 | 
			
		||||
	{"Handset Spk", NULL, "ROUT2"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("GSM Line Out"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("GSM Line In"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Headset Mic"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Handset Mic"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Handset Spk"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Stereo Out"),
 | 
			
		||||
 | 
			
		||||
	SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
 | 
			
		||||
		lm4853_get_spk,
 | 
			
		||||
		lm4853_set_spk),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_card *card = rtd->card;
 | 
			
		||||
 | 
			
		||||
	/* set endpoints to default off mode */
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic");
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic");
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out");
 | 
			
		||||
	snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk");
 | 
			
		||||
 | 
			
		||||
	/* allow audio paths from the GSM modem to run during suspend */
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out");
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In");
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic");
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out");
 | 
			
		||||
	snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(wm8753,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(bluetooth,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-voice")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link neo1973_dai[] = {
 | 
			
		||||
{ /* Hifi Playback - for similatious use with voice below */
 | 
			
		||||
	.name = "WM8753",
 | 
			
		||||
	.stream_name = "WM8753 HiFi",
 | 
			
		||||
	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
		   SND_SOC_DAIFMT_CBM_CFM,
 | 
			
		||||
	.init = neo1973_wm8753_init,
 | 
			
		||||
	.ops = &neo1973_hifi_ops,
 | 
			
		||||
	SND_SOC_DAILINK_REG(wm8753),
 | 
			
		||||
},
 | 
			
		||||
{ /* Voice via BT */
 | 
			
		||||
	.name = "Bluetooth",
 | 
			
		||||
	.stream_name = "Voice",
 | 
			
		||||
	.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
		   SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
	.ops = &neo1973_voice_ops,
 | 
			
		||||
	SND_SOC_DAILINK_REG(bluetooth),
 | 
			
		||||
},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_aux_dev neo1973_aux_devs[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.dlc = COMP_AUX("dfbmcs320.0"),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_codec_conf neo1973_codec_conf[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.dlc = COMP_CODEC_CONF("lm4857.0-007c"),
 | 
			
		||||
		.name_prefix = "Amp",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card neo1973 = {
 | 
			
		||||
	.name = "neo1973gta02",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = neo1973_dai,
 | 
			
		||||
	.num_links = ARRAY_SIZE(neo1973_dai),
 | 
			
		||||
	.aux_dev = neo1973_aux_devs,
 | 
			
		||||
	.num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
 | 
			
		||||
	.codec_conf = neo1973_codec_conf,
 | 
			
		||||
	.num_configs = ARRAY_SIZE(neo1973_codec_conf),
 | 
			
		||||
 | 
			
		||||
	.controls = neo1973_wm8753_controls,
 | 
			
		||||
	.num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
 | 
			
		||||
	.dapm_widgets = neo1973_wm8753_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
 | 
			
		||||
	.dapm_routes = neo1973_wm8753_routes,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
 | 
			
		||||
	.fully_routed = true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int neo1973_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
 | 
			
		||||
	gpiod_hp_in = devm_gpiod_get(dev, "hp", GPIOD_OUT_HIGH);
 | 
			
		||||
	if (IS_ERR(gpiod_hp_in)) {
 | 
			
		||||
		dev_err(dev, "missing gpio %s\n", "hp");
 | 
			
		||||
		return PTR_ERR(gpiod_hp_in);
 | 
			
		||||
	}
 | 
			
		||||
	gpiod_amp_shut = devm_gpiod_get(dev, "amp-shut", GPIOD_OUT_HIGH);
 | 
			
		||||
	if (IS_ERR(gpiod_amp_shut)) {
 | 
			
		||||
		dev_err(dev, "missing gpio %s\n", "amp-shut");
 | 
			
		||||
		return PTR_ERR(gpiod_amp_shut);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	neo1973.dev = dev;
 | 
			
		||||
	return devm_snd_soc_register_card(dev, &neo1973);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver neo1973_audio = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "neo1973-audio",
 | 
			
		||||
		.pm = &snd_soc_pm_ops,
 | 
			
		||||
	},
 | 
			
		||||
	.probe = neo1973_probe,
 | 
			
		||||
};
 | 
			
		||||
module_platform_driver(neo1973_audio);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("platform:neo1973-audio");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,111 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
 | 
			
		||||
 *	http://armlinux.simtec.co.uk/
 | 
			
		||||
 *
 | 
			
		||||
 * S3C2412 IIS register definition
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
 | 
			
		||||
#define __ASM_ARCH_REGS_S3C2412_IIS_H
 | 
			
		||||
 | 
			
		||||
#define S3C2412_IISCON			(0x00)
 | 
			
		||||
#define S3C2412_IISMOD			(0x04)
 | 
			
		||||
#define S3C2412_IISFIC			(0x08)
 | 
			
		||||
#define S3C2412_IISPSR			(0x0C)
 | 
			
		||||
#define S3C2412_IISTXD			(0x10)
 | 
			
		||||
#define S3C2412_IISRXD			(0x14)
 | 
			
		||||
 | 
			
		||||
#define S5PC1XX_IISFICS		0x18
 | 
			
		||||
#define S5PC1XX_IISTXDS		0x1C
 | 
			
		||||
 | 
			
		||||
#define S5PC1XX_IISCON_SW_RST		(1 << 31)
 | 
			
		||||
#define S5PC1XX_IISCON_FRXOFSTATUS	(1 << 26)
 | 
			
		||||
#define S5PC1XX_IISCON_FRXORINTEN	(1 << 25)
 | 
			
		||||
#define S5PC1XX_IISCON_FTXSURSTAT	(1 << 24)
 | 
			
		||||
#define S5PC1XX_IISCON_FTXSURINTEN	(1 << 23)
 | 
			
		||||
#define S5PC1XX_IISCON_TXSDMAPAUSE	(1 << 20)
 | 
			
		||||
#define S5PC1XX_IISCON_TXSDMACTIVE	(1 << 18)
 | 
			
		||||
 | 
			
		||||
#define S3C64XX_IISCON_FTXURSTATUS	(1 << 17)
 | 
			
		||||
#define S3C64XX_IISCON_FTXURINTEN	(1 << 16)
 | 
			
		||||
#define S3C64XX_IISCON_TXFIFO2_EMPTY	(1 << 15)
 | 
			
		||||
#define S3C64XX_IISCON_TXFIFO1_EMPTY	(1 << 14)
 | 
			
		||||
#define S3C64XX_IISCON_TXFIFO2_FULL	(1 << 13)
 | 
			
		||||
#define S3C64XX_IISCON_TXFIFO1_FULL	(1 << 12)
 | 
			
		||||
 | 
			
		||||
#define S3C2412_IISCON_LRINDEX		(1 << 11)
 | 
			
		||||
#define S3C2412_IISCON_TXFIFO_EMPTY	(1 << 10)
 | 
			
		||||
#define S3C2412_IISCON_RXFIFO_EMPTY	(1 << 9)
 | 
			
		||||
#define S3C2412_IISCON_TXFIFO_FULL	(1 << 8)
 | 
			
		||||
#define S3C2412_IISCON_RXFIFO_FULL	(1 << 7)
 | 
			
		||||
#define S3C2412_IISCON_TXDMA_PAUSE	(1 << 6)
 | 
			
		||||
#define S3C2412_IISCON_RXDMA_PAUSE	(1 << 5)
 | 
			
		||||
#define S3C2412_IISCON_TXCH_PAUSE	(1 << 4)
 | 
			
		||||
#define S3C2412_IISCON_RXCH_PAUSE	(1 << 3)
 | 
			
		||||
#define S3C2412_IISCON_TXDMA_ACTIVE	(1 << 2)
 | 
			
		||||
#define S3C2412_IISCON_RXDMA_ACTIVE	(1 << 1)
 | 
			
		||||
#define S3C2412_IISCON_IIS_ACTIVE	(1 << 0)
 | 
			
		||||
 | 
			
		||||
#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT	(0 << 30)
 | 
			
		||||
#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN	(1 << 30)
 | 
			
		||||
#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT	(2 << 30)
 | 
			
		||||
#define S5PC1XX_IISMOD_OPCLK_PCLK	(3 << 30)
 | 
			
		||||
#define S5PC1XX_IISMOD_OPCLK_MASK	(3 << 30)
 | 
			
		||||
#define S5PC1XX_IISMOD_TXS_IDMA		(1 << 28) /* Sec_TXFIFO use I-DMA */
 | 
			
		||||
#define S5PC1XX_IISMOD_BLCS_MASK	0x3
 | 
			
		||||
#define S5PC1XX_IISMOD_BLCS_SHIFT	26
 | 
			
		||||
#define S5PC1XX_IISMOD_BLCP_MASK	0x3
 | 
			
		||||
#define S5PC1XX_IISMOD_BLCP_SHIFT	24
 | 
			
		||||
 | 
			
		||||
#define S3C64XX_IISMOD_C2DD_HHALF	(1 << 21) /* Discard Higher-half */
 | 
			
		||||
#define S3C64XX_IISMOD_C2DD_LHALF	(1 << 20) /* Discard Lower-half */
 | 
			
		||||
#define S3C64XX_IISMOD_C1DD_HHALF	(1 << 19)
 | 
			
		||||
#define S3C64XX_IISMOD_C1DD_LHALF	(1 << 18)
 | 
			
		||||
#define S3C64XX_IISMOD_DC2_EN		(1 << 17)
 | 
			
		||||
#define S3C64XX_IISMOD_DC1_EN		(1 << 16)
 | 
			
		||||
#define S3C64XX_IISMOD_BLC_16BIT	(0 << 13)
 | 
			
		||||
#define S3C64XX_IISMOD_BLC_8BIT		(1 << 13)
 | 
			
		||||
#define S3C64XX_IISMOD_BLC_24BIT	(2 << 13)
 | 
			
		||||
#define S3C64XX_IISMOD_BLC_MASK		(3 << 13)
 | 
			
		||||
 | 
			
		||||
#define S3C2412_IISMOD_IMS_SYSMUX	(1 << 10)
 | 
			
		||||
#define S3C2412_IISMOD_SLAVE		(1 << 11)
 | 
			
		||||
#define S3C2412_IISMOD_MODE_TXONLY	(0 << 8)
 | 
			
		||||
#define S3C2412_IISMOD_MODE_RXONLY	(1 << 8)
 | 
			
		||||
#define S3C2412_IISMOD_MODE_TXRX	(2 << 8)
 | 
			
		||||
#define S3C2412_IISMOD_MODE_MASK	(3 << 8)
 | 
			
		||||
#define S3C2412_IISMOD_LR_LLOW		(0 << 7)
 | 
			
		||||
#define S3C2412_IISMOD_LR_RLOW		(1 << 7)
 | 
			
		||||
#define S3C2412_IISMOD_SDF_IIS		(0 << 5)
 | 
			
		||||
#define S3C2412_IISMOD_SDF_MSB		(1 << 5)
 | 
			
		||||
#define S3C2412_IISMOD_SDF_LSB		(2 << 5)
 | 
			
		||||
#define S3C2412_IISMOD_SDF_MASK		(3 << 5)
 | 
			
		||||
#define S3C2412_IISMOD_RCLK_256FS	(0 << 3)
 | 
			
		||||
#define S3C2412_IISMOD_RCLK_512FS	(1 << 3)
 | 
			
		||||
#define S3C2412_IISMOD_RCLK_384FS	(2 << 3)
 | 
			
		||||
#define S3C2412_IISMOD_RCLK_768FS	(3 << 3)
 | 
			
		||||
#define S3C2412_IISMOD_RCLK_MASK 	(3 << 3)
 | 
			
		||||
#define S3C2412_IISMOD_BCLK_32FS	(0 << 1)
 | 
			
		||||
#define S3C2412_IISMOD_BCLK_48FS	(1 << 1)
 | 
			
		||||
#define S3C2412_IISMOD_BCLK_16FS	(2 << 1)
 | 
			
		||||
#define S3C2412_IISMOD_BCLK_24FS	(3 << 1)
 | 
			
		||||
#define S3C2412_IISMOD_BCLK_MASK	(3 << 1)
 | 
			
		||||
#define S3C2412_IISMOD_8BIT		(1 << 0)
 | 
			
		||||
 | 
			
		||||
#define S3C64XX_IISMOD_CDCLKCON		(1 << 12)
 | 
			
		||||
 | 
			
		||||
#define S3C2412_IISPSR_PSREN		(1 << 15)
 | 
			
		||||
 | 
			
		||||
#define S3C64XX_IISFIC_TX2COUNT(x)	(((x) >>  24) & 0xf)
 | 
			
		||||
#define S3C64XX_IISFIC_TX1COUNT(x)	(((x) >>  16) & 0xf)
 | 
			
		||||
 | 
			
		||||
#define S3C2412_IISFIC_TXFLUSH		(1 << 15)
 | 
			
		||||
#define S3C2412_IISFIC_RXFLUSH		(1 << 7)
 | 
			
		||||
#define S3C2412_IISFIC_TXCOUNT(x)	(((x) >>  8) & 0xf)
 | 
			
		||||
#define S3C2412_IISFIC_RXCOUNT(x)	(((x) >>  0) & 0xf)
 | 
			
		||||
 | 
			
		||||
#define S5PC1XX_IISFICS_TXFLUSH		(1 << 15)
 | 
			
		||||
#define S5PC1XX_IISFICS_TXCOUNT(x)	(((x) >>  8) & 0x7f)
 | 
			
		||||
 | 
			
		||||
#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,66 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
 | 
			
		||||
 *		      http://www.simtec.co.uk/products/SWLINUX/
 | 
			
		||||
 *
 | 
			
		||||
 * S3C2410 IIS register definition
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __SAMSUNG_REGS_IIS_H__
 | 
			
		||||
#define __SAMSUNG_REGS_IIS_H__
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISCON			(0x00)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISCON_LRINDEX		(1 << 8)
 | 
			
		||||
#define S3C2410_IISCON_TXFIFORDY	(1 << 7)
 | 
			
		||||
#define S3C2410_IISCON_RXFIFORDY	(1 << 6)
 | 
			
		||||
#define S3C2410_IISCON_TXDMAEN		(1 << 5)
 | 
			
		||||
#define S3C2410_IISCON_RXDMAEN		(1 << 4)
 | 
			
		||||
#define S3C2410_IISCON_TXIDLE		(1 << 3)
 | 
			
		||||
#define S3C2410_IISCON_RXIDLE		(1 << 2)
 | 
			
		||||
#define S3C2410_IISCON_PSCEN		(1 << 1)
 | 
			
		||||
#define S3C2410_IISCON_IISEN		(1 << 0)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISMOD			(0x04)
 | 
			
		||||
 | 
			
		||||
#define S3C2440_IISMOD_MPLL		(1 << 9)
 | 
			
		||||
#define S3C2410_IISMOD_SLAVE		(1 << 8)
 | 
			
		||||
#define S3C2410_IISMOD_NOXFER		(0 << 6)
 | 
			
		||||
#define S3C2410_IISMOD_RXMODE		(1 << 6)
 | 
			
		||||
#define S3C2410_IISMOD_TXMODE		(2 << 6)
 | 
			
		||||
#define S3C2410_IISMOD_TXRXMODE		(3 << 6)
 | 
			
		||||
#define S3C2410_IISMOD_LR_LLOW		(0 << 5)
 | 
			
		||||
#define S3C2410_IISMOD_LR_RLOW		(1 << 5)
 | 
			
		||||
#define S3C2410_IISMOD_IIS		(0 << 4)
 | 
			
		||||
#define S3C2410_IISMOD_MSB		(1 << 4)
 | 
			
		||||
#define S3C2410_IISMOD_8BIT		(0 << 3)
 | 
			
		||||
#define S3C2410_IISMOD_16BIT		(1 << 3)
 | 
			
		||||
#define S3C2410_IISMOD_BITMASK		(1 << 3)
 | 
			
		||||
#define S3C2410_IISMOD_256FS		(0 << 2)
 | 
			
		||||
#define S3C2410_IISMOD_384FS		(1 << 2)
 | 
			
		||||
#define S3C2410_IISMOD_16FS		(0 << 0)
 | 
			
		||||
#define S3C2410_IISMOD_32FS		(1 << 0)
 | 
			
		||||
#define S3C2410_IISMOD_48FS		(2 << 0)
 | 
			
		||||
#define S3C2410_IISMOD_FS_MASK		(3 << 0)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISPSR			(0x08)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISPSR_INTMASK		(31 << 5)
 | 
			
		||||
#define S3C2410_IISPSR_INTSHIFT		(5)
 | 
			
		||||
#define S3C2410_IISPSR_EXTMASK		(31 << 0)
 | 
			
		||||
#define S3C2410_IISPSR_EXTSHFIT		(0)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISFCON			(0x0c)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISFCON_TXDMA		(1 << 15)
 | 
			
		||||
#define S3C2410_IISFCON_RXDMA		(1 << 14)
 | 
			
		||||
#define S3C2410_IISFCON_TXENABLE	(1 << 13)
 | 
			
		||||
#define S3C2410_IISFCON_RXENABLE	(1 << 12)
 | 
			
		||||
#define S3C2410_IISFCON_TXMASK		(0x3f << 6)
 | 
			
		||||
#define S3C2410_IISFCON_TXSHIFT		(6)
 | 
			
		||||
#define S3C2410_IISFCON_RXMASK		(0x3f)
 | 
			
		||||
#define S3C2410_IISFCON_RXSHIFT		(0)
 | 
			
		||||
 | 
			
		||||
#define S3C2410_IISFIFO			(0x10)
 | 
			
		||||
 | 
			
		||||
#endif /* __SAMSUNG_REGS_IIS_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,245 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// rx1950.c - ALSA SoC Audio Layer
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
 | 
			
		||||
//
 | 
			
		||||
// Based on smdk2440.c and magician.c
 | 
			
		||||
//
 | 
			
		||||
// Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
 | 
			
		||||
//          Philipp Zabel <philipp.zabel@gmail.com>
 | 
			
		||||
//          Denis Grigoriev <dgreenday@gmail.com>
 | 
			
		||||
//          Vasily Khoruzhick <anarsoul@gmail.com>
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/gpio/consumer.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/jack.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-iis.h"
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
 | 
			
		||||
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
 | 
			
		||||
static int rx1950_startup(struct snd_pcm_substream *substream);
 | 
			
		||||
static int rx1950_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				struct snd_pcm_hw_params *params);
 | 
			
		||||
static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
 | 
			
		||||
				struct snd_kcontrol *kcontrol, int event);
 | 
			
		||||
 | 
			
		||||
static const unsigned int rates[] = {
 | 
			
		||||
	16000,
 | 
			
		||||
	44100,
 | 
			
		||||
	48000,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_pcm_hw_constraint_list hw_rates = {
 | 
			
		||||
	.count = ARRAY_SIZE(rates),
 | 
			
		||||
	.list = rates,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack hp_jack;
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_pin hp_jack_pins[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.pin	= "Headphone Jack",
 | 
			
		||||
		.mask	= SND_JACK_HEADPHONE,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.pin	= "Speaker",
 | 
			
		||||
		.mask	= SND_JACK_HEADPHONE,
 | 
			
		||||
		.invert	= 1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_gpio hp_jack_gpios[] = {
 | 
			
		||||
	[0] = {
 | 
			
		||||
		.name			= "hp-gpio",
 | 
			
		||||
		.report			= SND_JACK_HEADPHONE,
 | 
			
		||||
		.invert			= 1,
 | 
			
		||||
		.debounce_time		= 200,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops rx1950_ops = {
 | 
			
		||||
	.startup	= rx1950_startup,
 | 
			
		||||
	.hw_params	= rx1950_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* s3c24xx digital audio interface glue - connects codec <--> CPU */
 | 
			
		||||
SND_SOC_DAILINK_DEFS(uda1380,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-001a",
 | 
			
		||||
				      "uda1380-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name		= "uda1380",
 | 
			
		||||
		.stream_name	= "UDA1380 Duplex",
 | 
			
		||||
		.init		= rx1950_uda1380_init,
 | 
			
		||||
		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
				  SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
		.ops		= &rx1950_ops,
 | 
			
		||||
		SND_SOC_DAILINK_REG(uda1380),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* rx1950 machine dapm widgets */
 | 
			
		||||
static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* rx1950 machine audio_map */
 | 
			
		||||
static const struct snd_soc_dapm_route audio_map[] = {
 | 
			
		||||
	/* headphone connected to VOUTLHP, VOUTRHP */
 | 
			
		||||
	{"Headphone Jack", NULL, "VOUTLHP"},
 | 
			
		||||
	{"Headphone Jack", NULL, "VOUTRHP"},
 | 
			
		||||
 | 
			
		||||
	/* ext speaker connected to VOUTL, VOUTR  */
 | 
			
		||||
	{"Speaker", NULL, "VOUTL"},
 | 
			
		||||
	{"Speaker", NULL, "VOUTR"},
 | 
			
		||||
 | 
			
		||||
	/* mic is connected to VINM */
 | 
			
		||||
	{"VINM", NULL, "Mic Jack"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card rx1950_asoc = {
 | 
			
		||||
	.name = "rx1950",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = rx1950_uda1380_dai,
 | 
			
		||||
	.num_links = ARRAY_SIZE(rx1950_uda1380_dai),
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets = uda1380_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
 | 
			
		||||
	.dapm_routes = audio_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(audio_map),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int rx1950_startup(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_pcm_runtime *runtime = substream->runtime;
 | 
			
		||||
 | 
			
		||||
	return snd_pcm_hw_constraint_list(runtime, 0,
 | 
			
		||||
					SNDRV_PCM_HW_PARAM_RATE,
 | 
			
		||||
					&hw_rates);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gpio_desc *gpiod_speaker_power;
 | 
			
		||||
 | 
			
		||||
static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
 | 
			
		||||
				struct snd_kcontrol *kcontrol, int event)
 | 
			
		||||
{
 | 
			
		||||
	if (SND_SOC_DAPM_EVENT_ON(event))
 | 
			
		||||
		gpiod_set_value(gpiod_speaker_power, 1);
 | 
			
		||||
	else
 | 
			
		||||
		gpiod_set_value(gpiod_speaker_power, 0);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx1950_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	int div;
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned int rate = params_rate(params);
 | 
			
		||||
	int clk_source, fs_mode;
 | 
			
		||||
 | 
			
		||||
	switch (rate) {
 | 
			
		||||
	case 16000:
 | 
			
		||||
	case 48000:
 | 
			
		||||
		clk_source = S3C24XX_CLKSRC_PCLK;
 | 
			
		||||
		fs_mode = S3C2410_IISMOD_256FS;
 | 
			
		||||
		div = s3c24xx_i2s_get_clockrate() / (256 * rate);
 | 
			
		||||
		if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
 | 
			
		||||
			div++;
 | 
			
		||||
		break;
 | 
			
		||||
	case 44100:
 | 
			
		||||
	case 88200:
 | 
			
		||||
		clk_source = S3C24XX_CLKSRC_MPLL;
 | 
			
		||||
		fs_mode = S3C2410_IISMOD_384FS;
 | 
			
		||||
		div = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		printk(KERN_ERR "%s: rate %d is not supported\n",
 | 
			
		||||
			__func__, rate);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* select clock source */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
 | 
			
		||||
			SND_SOC_CLOCK_OUT);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set MCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
 | 
			
		||||
		fs_mode);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set BCLK division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
 | 
			
		||||
		S3C2410_IISMOD_32FS);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set prescaler division for sample rate */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 | 
			
		||||
		S3C24XX_PRESCALE(div, div));
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
 | 
			
		||||
		SND_JACK_HEADPHONE,
 | 
			
		||||
		&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 | 
			
		||||
 | 
			
		||||
	snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
 | 
			
		||||
		hp_jack_gpios);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx1950_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
 | 
			
		||||
	/* configure some gpios */
 | 
			
		||||
	gpiod_speaker_power = devm_gpiod_get(dev, "speaker-power", GPIOD_OUT_LOW);
 | 
			
		||||
	if (IS_ERR(gpiod_speaker_power)) {
 | 
			
		||||
		dev_err(dev, "cannot get gpio\n");
 | 
			
		||||
		return PTR_ERR(gpiod_speaker_power);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hp_jack_gpios[0].gpiod_dev = dev;
 | 
			
		||||
	rx1950_asoc.dev = dev;
 | 
			
		||||
 | 
			
		||||
	return devm_snd_soc_register_card(dev, &rx1950_asoc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver rx1950_audio = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "rx1950-audio",
 | 
			
		||||
		.pm = &snd_soc_pm_ops,
 | 
			
		||||
	},
 | 
			
		||||
	.probe = rx1950_probe,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(rx1950_audio);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Vasily Khoruzhick");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC RX1950");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("platform:rx1950-audio");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,670 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2006 Wolfson Microelectronics PLC.
 | 
			
		||||
//	Graeme Gregory graeme.gregory@wolfsonmicro.com
 | 
			
		||||
//	linux@wolfsonmicro.com
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
 | 
			
		||||
//	http://armlinux.simtec.co.uk/
 | 
			
		||||
//	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/pcm_params.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-i2s-v2.h"
 | 
			
		||||
#include "s3c-i2s-v2.h"
 | 
			
		||||
 | 
			
		||||
#define S3C2412_I2S_DEBUG_CON 0
 | 
			
		||||
 | 
			
		||||
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
 | 
			
		||||
{
 | 
			
		||||
	return snd_soc_dai_get_drvdata(cpu_dai);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
 | 
			
		||||
 | 
			
		||||
#if S3C2412_I2S_DEBUG_CON
 | 
			
		||||
static void dbg_showcon(const char *fn, u32 con)
 | 
			
		||||
{
 | 
			
		||||
	printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_LRINDEX),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
 | 
			
		||||
 | 
			
		||||
	printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
 | 
			
		||||
	       fn,
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
 | 
			
		||||
	printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
 | 
			
		||||
	       bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline void dbg_showcon(const char *fn, u32 con)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Turn on or off the transmission path. */
 | 
			
		||||
static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *regs = i2s->regs;
 | 
			
		||||
	u32 fic, con, mod;
 | 
			
		||||
 | 
			
		||||
	pr_debug("%s(%d)\n", __func__, on);
 | 
			
		||||
 | 
			
		||||
	fic = readl(regs + S3C2412_IISFIC);
 | 
			
		||||
	con = readl(regs + S3C2412_IISCON);
 | 
			
		||||
	mod = readl(regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 | 
			
		||||
 | 
			
		||||
	if (on) {
 | 
			
		||||
		con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
 | 
			
		||||
		con &= ~S3C2412_IISCON_TXDMA_PAUSE;
 | 
			
		||||
		con &= ~S3C2412_IISCON_TXCH_PAUSE;
 | 
			
		||||
 | 
			
		||||
		switch (mod & S3C2412_IISMOD_MODE_MASK) {
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXONLY:
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXRX:
 | 
			
		||||
			/* do nothing, we are in the right mode */
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case S3C2412_IISMOD_MODE_RXONLY:
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			mod |= S3C2412_IISMOD_MODE_TXRX;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
 | 
			
		||||
				mod & S3C2412_IISMOD_MODE_MASK);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writel(con, regs + S3C2412_IISCON);
 | 
			
		||||
		writel(mod, regs + S3C2412_IISMOD);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Note, we do not have any indication that the FIFO problems
 | 
			
		||||
		 * tha the S3C2410/2440 had apply here, so we should be able
 | 
			
		||||
		 * to disable the DMA and TX without resetting the FIFOS.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		con |=  S3C2412_IISCON_TXDMA_PAUSE;
 | 
			
		||||
		con |=  S3C2412_IISCON_TXCH_PAUSE;
 | 
			
		||||
		con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
 | 
			
		||||
 | 
			
		||||
		switch (mod & S3C2412_IISMOD_MODE_MASK) {
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXRX:
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			mod |= S3C2412_IISMOD_MODE_RXONLY;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXONLY:
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			con &= ~S3C2412_IISCON_IIS_ACTIVE;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
 | 
			
		||||
				mod & S3C2412_IISMOD_MODE_MASK);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writel(mod, regs + S3C2412_IISMOD);
 | 
			
		||||
		writel(con, regs + S3C2412_IISCON);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fic = readl(regs + S3C2412_IISFIC);
 | 
			
		||||
	dbg_showcon(__func__, con);
 | 
			
		||||
	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *regs = i2s->regs;
 | 
			
		||||
	u32 fic, con, mod;
 | 
			
		||||
 | 
			
		||||
	pr_debug("%s(%d)\n", __func__, on);
 | 
			
		||||
 | 
			
		||||
	fic = readl(regs + S3C2412_IISFIC);
 | 
			
		||||
	con = readl(regs + S3C2412_IISCON);
 | 
			
		||||
	mod = readl(regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 | 
			
		||||
 | 
			
		||||
	if (on) {
 | 
			
		||||
		con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
 | 
			
		||||
		con &= ~S3C2412_IISCON_RXDMA_PAUSE;
 | 
			
		||||
		con &= ~S3C2412_IISCON_RXCH_PAUSE;
 | 
			
		||||
 | 
			
		||||
		switch (mod & S3C2412_IISMOD_MODE_MASK) {
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXRX:
 | 
			
		||||
		case S3C2412_IISMOD_MODE_RXONLY:
 | 
			
		||||
			/* do nothing, we are in the right mode */
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXONLY:
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			mod |= S3C2412_IISMOD_MODE_TXRX;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
 | 
			
		||||
				mod & S3C2412_IISMOD_MODE_MASK);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writel(mod, regs + S3C2412_IISMOD);
 | 
			
		||||
		writel(con, regs + S3C2412_IISCON);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* See txctrl notes on FIFOs. */
 | 
			
		||||
 | 
			
		||||
		con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
 | 
			
		||||
		con |=  S3C2412_IISCON_RXDMA_PAUSE;
 | 
			
		||||
		con |=  S3C2412_IISCON_RXCH_PAUSE;
 | 
			
		||||
 | 
			
		||||
		switch (mod & S3C2412_IISMOD_MODE_MASK) {
 | 
			
		||||
		case S3C2412_IISMOD_MODE_RXONLY:
 | 
			
		||||
			con &= ~S3C2412_IISCON_IIS_ACTIVE;
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case S3C2412_IISMOD_MODE_TXRX:
 | 
			
		||||
			mod &= ~S3C2412_IISMOD_MODE_MASK;
 | 
			
		||||
			mod |= S3C2412_IISMOD_MODE_TXONLY;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
 | 
			
		||||
				mod & S3C2412_IISMOD_MODE_MASK);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writel(con, regs + S3C2412_IISCON);
 | 
			
		||||
		writel(mod, regs + S3C2412_IISMOD);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fic = readl(regs + S3C2412_IISFIC);
 | 
			
		||||
	pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Wait for the LR signal to allow synchronisation to the L/R clock
 | 
			
		||||
 * from the codec. May only be needed for slave mode.
 | 
			
		||||
 */
 | 
			
		||||
static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
 | 
			
		||||
{
 | 
			
		||||
	u32 iiscon;
 | 
			
		||||
	unsigned long loops = msecs_to_loops(5);
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	while (--loops) {
 | 
			
		||||
		iiscon = readl(i2s->regs + S3C2412_IISCON);
 | 
			
		||||
		if (iiscon & S3C2412_IISCON_LRINDEX)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		cpu_relax();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!loops) {
 | 
			
		||||
		printk(KERN_ERR "%s: timeout\n", __func__);
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set S3C2412 I2S DAI format
 | 
			
		||||
 */
 | 
			
		||||
static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
			       unsigned int fmt)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("hw_params r: IISMOD: %x \n", iismod);
 | 
			
		||||
 | 
			
		||||
	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
 | 
			
		||||
	case SND_SOC_DAIFMT_BC_FC:
 | 
			
		||||
		i2s->master = 0;
 | 
			
		||||
		iismod |= S3C2412_IISMOD_SLAVE;
 | 
			
		||||
		break;
 | 
			
		||||
	case SND_SOC_DAIFMT_BP_FP:
 | 
			
		||||
		i2s->master = 1;
 | 
			
		||||
		iismod &= ~S3C2412_IISMOD_SLAVE;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		pr_err("unknown master/slave format\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iismod &= ~S3C2412_IISMOD_SDF_MASK;
 | 
			
		||||
 | 
			
		||||
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 | 
			
		||||
	case SND_SOC_DAIFMT_RIGHT_J:
 | 
			
		||||
		iismod |= S3C2412_IISMOD_LR_RLOW;
 | 
			
		||||
		iismod |= S3C2412_IISMOD_SDF_MSB;
 | 
			
		||||
		break;
 | 
			
		||||
	case SND_SOC_DAIFMT_LEFT_J:
 | 
			
		||||
		iismod |= S3C2412_IISMOD_LR_RLOW;
 | 
			
		||||
		iismod |= S3C2412_IISMOD_SDF_LSB;
 | 
			
		||||
		break;
 | 
			
		||||
	case SND_SOC_DAIFMT_I2S:
 | 
			
		||||
		iismod &= ~S3C2412_IISMOD_LR_RLOW;
 | 
			
		||||
		iismod |= S3C2412_IISMOD_SDF_IIS;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		pr_err("Unknown data format\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("hw_params w: IISMOD: %x \n", iismod);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				 struct snd_pcm_hw_params *params,
 | 
			
		||||
				 struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(dai);
 | 
			
		||||
	struct snd_dmaengine_dai_dma_data *dma_data;
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 | 
			
		||||
		dma_data = i2s->dma_playback;
 | 
			
		||||
	else
 | 
			
		||||
		dma_data = i2s->dma_capture;
 | 
			
		||||
 | 
			
		||||
	snd_soc_dai_set_dma_data(dai, substream, dma_data);
 | 
			
		||||
 | 
			
		||||
	/* Working copies of register */
 | 
			
		||||
	iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	iismod &= ~S3C64XX_IISMOD_BLC_MASK;
 | 
			
		||||
	/* Sample size */
 | 
			
		||||
	switch (params_width(params)) {
 | 
			
		||||
	case 8:
 | 
			
		||||
		iismod |= S3C64XX_IISMOD_BLC_8BIT;
 | 
			
		||||
		break;
 | 
			
		||||
	case 16:
 | 
			
		||||
		break;
 | 
			
		||||
	case 24:
 | 
			
		||||
		iismod |= S3C64XX_IISMOD_BLC_24BIT;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
				  int clk_id, unsigned int freq, int dir)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 | 
			
		||||
	u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
	pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	switch (clk_id) {
 | 
			
		||||
	case S3C_I2SV2_CLKSRC_PCLK:
 | 
			
		||||
		iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case S3C_I2SV2_CLKSRC_AUDIOBUS:
 | 
			
		||||
		iismod |= S3C2412_IISMOD_IMS_SYSMUX;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case S3C_I2SV2_CLKSRC_CDCLK:
 | 
			
		||||
		/* Error if controller doesn't have the CDCLKCON bit */
 | 
			
		||||
		if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		switch (dir) {
 | 
			
		||||
		case SND_SOC_CLOCK_IN:
 | 
			
		||||
			iismod |= S3C64XX_IISMOD_CDCLKCON;
 | 
			
		||||
			break;
 | 
			
		||||
		case SND_SOC_CLOCK_OUT:
 | 
			
		||||
			iismod &= ~S3C64XX_IISMOD_CDCLKCON;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 | 
			
		||||
			       struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
 | 
			
		||||
	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 | 
			
		||||
	unsigned long irqs;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_START:
 | 
			
		||||
		/* On start, ensure that the FIFOs are cleared and reset. */
 | 
			
		||||
 | 
			
		||||
		writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
 | 
			
		||||
		       i2s->regs + S3C2412_IISFIC);
 | 
			
		||||
 | 
			
		||||
		/* clear again, just in case */
 | 
			
		||||
		writel(0x0, i2s->regs + S3C2412_IISFIC);
 | 
			
		||||
 | 
			
		||||
		fallthrough;
 | 
			
		||||
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_RESUME:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 | 
			
		||||
		if (!i2s->master) {
 | 
			
		||||
			ret = s3c2412_snd_lrsync(i2s);
 | 
			
		||||
			if (ret)
 | 
			
		||||
				goto exit_err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		local_irq_save(irqs);
 | 
			
		||||
 | 
			
		||||
		if (capture)
 | 
			
		||||
			s3c2412_snd_rxctrl(i2s, 1);
 | 
			
		||||
		else
 | 
			
		||||
			s3c2412_snd_txctrl(i2s, 1);
 | 
			
		||||
 | 
			
		||||
		local_irq_restore(irqs);
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_STOP:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_SUSPEND:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 | 
			
		||||
		local_irq_save(irqs);
 | 
			
		||||
 | 
			
		||||
		if (capture)
 | 
			
		||||
			s3c2412_snd_rxctrl(i2s, 0);
 | 
			
		||||
		else
 | 
			
		||||
			s3c2412_snd_txctrl(i2s, 0);
 | 
			
		||||
 | 
			
		||||
		local_irq_restore(irqs);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
exit_err:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set S3C2412 Clock dividers
 | 
			
		||||
 */
 | 
			
		||||
static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
				  int div_id, int div)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 | 
			
		||||
	u32 reg;
 | 
			
		||||
 | 
			
		||||
	pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
 | 
			
		||||
 | 
			
		||||
	switch (div_id) {
 | 
			
		||||
	case S3C_I2SV2_DIV_BCLK:
 | 
			
		||||
		switch (div) {
 | 
			
		||||
		case 16:
 | 
			
		||||
			div = S3C2412_IISMOD_BCLK_16FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 32:
 | 
			
		||||
			div = S3C2412_IISMOD_BCLK_32FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 24:
 | 
			
		||||
			div = S3C2412_IISMOD_BCLK_24FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 48:
 | 
			
		||||
			div = S3C2412_IISMOD_BCLK_48FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reg = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
		reg &= ~S3C2412_IISMOD_BCLK_MASK;
 | 
			
		||||
		writel(reg | div, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
		pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case S3C_I2SV2_DIV_RCLK:
 | 
			
		||||
		switch (div) {
 | 
			
		||||
		case 256:
 | 
			
		||||
			div = S3C2412_IISMOD_RCLK_256FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 384:
 | 
			
		||||
			div = S3C2412_IISMOD_RCLK_384FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 512:
 | 
			
		||||
			div = S3C2412_IISMOD_RCLK_512FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case 768:
 | 
			
		||||
			div = S3C2412_IISMOD_RCLK_768FS;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reg = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
		reg &= ~S3C2412_IISMOD_RCLK_MASK;
 | 
			
		||||
		writel(reg | div, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
		pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case S3C_I2SV2_DIV_PRESCALER:
 | 
			
		||||
		if (div >= 0) {
 | 
			
		||||
			writel((div << 8) | S3C2412_IISPSR_PSREN,
 | 
			
		||||
			       i2s->regs + S3C2412_IISPSR);
 | 
			
		||||
		} else {
 | 
			
		||||
			writel(0x0, i2s->regs + S3C2412_IISPSR);
 | 
			
		||||
		}
 | 
			
		||||
		pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
 | 
			
		||||
					   struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(dai);
 | 
			
		||||
	u32 reg = readl(i2s->regs + S3C2412_IISFIC);
 | 
			
		||||
	snd_pcm_sframes_t delay;
 | 
			
		||||
 | 
			
		||||
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 | 
			
		||||
		delay = S3C2412_IISFIC_TXCOUNT(reg);
 | 
			
		||||
	else
 | 
			
		||||
		delay = S3C2412_IISFIC_RXCOUNT(reg);
 | 
			
		||||
 | 
			
		||||
	return delay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 | 
			
		||||
	u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
	if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
 | 
			
		||||
		return i2s->iis_cclk;
 | 
			
		||||
	else
 | 
			
		||||
		return i2s->iis_pclk;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
 | 
			
		||||
 | 
			
		||||
/* default table of all avaialable root fs divisors */
 | 
			
		||||
static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
 | 
			
		||||
 | 
			
		||||
int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 | 
			
		||||
			    unsigned int *fstab,
 | 
			
		||||
			    unsigned int rate, struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long clkrate = clk_get_rate(clk);
 | 
			
		||||
	unsigned int div;
 | 
			
		||||
	unsigned int fsclk;
 | 
			
		||||
	unsigned int actual;
 | 
			
		||||
	unsigned int fs;
 | 
			
		||||
	unsigned int fsdiv;
 | 
			
		||||
	signed int deviation = 0;
 | 
			
		||||
	unsigned int best_fs = 0;
 | 
			
		||||
	unsigned int best_div = 0;
 | 
			
		||||
	unsigned int best_rate = 0;
 | 
			
		||||
	unsigned int best_deviation = INT_MAX;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Input clock rate %ldHz\n", clkrate);
 | 
			
		||||
 | 
			
		||||
	if (fstab == NULL)
 | 
			
		||||
		fstab = iis_fs_tab;
 | 
			
		||||
 | 
			
		||||
	for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
 | 
			
		||||
		fsdiv = iis_fs_tab[fs];
 | 
			
		||||
 | 
			
		||||
		fsclk = clkrate / fsdiv;
 | 
			
		||||
		div = fsclk / rate;
 | 
			
		||||
 | 
			
		||||
		if ((fsclk % rate) > (rate / 2))
 | 
			
		||||
			div++;
 | 
			
		||||
 | 
			
		||||
		if (div <= 1)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		actual = clkrate / (fsdiv * div);
 | 
			
		||||
		deviation = actual - rate;
 | 
			
		||||
 | 
			
		||||
		printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
 | 
			
		||||
		       fsdiv, div, actual, deviation);
 | 
			
		||||
 | 
			
		||||
		deviation = abs(deviation);
 | 
			
		||||
 | 
			
		||||
		if (deviation < best_deviation) {
 | 
			
		||||
			best_fs = fsdiv;
 | 
			
		||||
			best_div = div;
 | 
			
		||||
			best_rate = actual;
 | 
			
		||||
			best_deviation = deviation;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (deviation == 0)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
 | 
			
		||||
	       best_fs, best_div, best_rate);
 | 
			
		||||
 | 
			
		||||
	info->fs_div = best_fs;
 | 
			
		||||
	info->clk_div = best_div;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
 | 
			
		||||
 | 
			
		||||
int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 | 
			
		||||
		    struct s3c_i2sv2_info *i2s)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = dai->dev;
 | 
			
		||||
	unsigned int iismod;
 | 
			
		||||
 | 
			
		||||
	i2s->dev = dev;
 | 
			
		||||
 | 
			
		||||
	/* record our i2s structure for later use in the callbacks */
 | 
			
		||||
	snd_soc_dai_set_drvdata(dai, i2s);
 | 
			
		||||
 | 
			
		||||
	i2s->iis_pclk = clk_get(dev, "iis");
 | 
			
		||||
	if (IS_ERR(i2s->iis_pclk)) {
 | 
			
		||||
		dev_err(dev, "failed to get iis_clock\n");
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk_prepare_enable(i2s->iis_pclk);
 | 
			
		||||
 | 
			
		||||
	/* Mark ourselves as in TXRX mode so we can run through our cleanup
 | 
			
		||||
	 * process without warnings. */
 | 
			
		||||
	iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	iismod |= S3C2412_IISMOD_MODE_TXRX;
 | 
			
		||||
	writel(iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	s3c2412_snd_txctrl(i2s, 0);
 | 
			
		||||
	s3c2412_snd_rxctrl(i2s, 0);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
 | 
			
		||||
 | 
			
		||||
void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
 | 
			
		||||
		      struct s3c_i2sv2_info *i2s)
 | 
			
		||||
{
 | 
			
		||||
	clk_disable_unprepare(i2s->iis_pclk);
 | 
			
		||||
	clk_put(i2s->iis_pclk);
 | 
			
		||||
	i2s->iis_pclk = NULL;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
 | 
			
		||||
 | 
			
		||||
int s3c_i2sv2_register_component(struct device *dev, int id,
 | 
			
		||||
			   const struct snd_soc_component_driver *cmp_drv,
 | 
			
		||||
			   struct snd_soc_dai_driver *dai_drv)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops;
 | 
			
		||||
 | 
			
		||||
	ops->trigger = s3c2412_i2s_trigger;
 | 
			
		||||
	if (!ops->hw_params)
 | 
			
		||||
		ops->hw_params = s3c_i2sv2_hw_params;
 | 
			
		||||
	ops->set_fmt = s3c2412_i2s_set_fmt;
 | 
			
		||||
	ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
 | 
			
		||||
	ops->set_sysclk = s3c_i2sv2_set_sysclk;
 | 
			
		||||
 | 
			
		||||
	/* Allow overriding by (for example) IISv4 */
 | 
			
		||||
	if (!ops->delay)
 | 
			
		||||
		ops->delay = s3c2412_i2s_delay;
 | 
			
		||||
 | 
			
		||||
	return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
 | 
			
		||||
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,108 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
			
		||||
/*
 | 
			
		||||
 * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2007 Simtec Electronics
 | 
			
		||||
 *	http://armlinux.simtec.co.uk/
 | 
			
		||||
 *	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* This code is the core support for the I2S block found in a number of
 | 
			
		||||
 * Samsung SoC devices which is unofficially named I2S-V2. Currently the
 | 
			
		||||
 * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
 | 
			
		||||
 * channels via configurable GPIO.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
 | 
			
		||||
#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
 | 
			
		||||
 | 
			
		||||
#define S3C_I2SV2_DIV_BCLK	(1)
 | 
			
		||||
#define S3C_I2SV2_DIV_RCLK	(2)
 | 
			
		||||
#define S3C_I2SV2_DIV_PRESCALER	(3)
 | 
			
		||||
 | 
			
		||||
#define S3C_I2SV2_CLKSRC_PCLK		0
 | 
			
		||||
#define S3C_I2SV2_CLKSRC_AUDIOBUS	1
 | 
			
		||||
#define S3C_I2SV2_CLKSRC_CDCLK		2
 | 
			
		||||
 | 
			
		||||
/* Set this flag for I2S controllers that have the bit IISMOD[12]
 | 
			
		||||
 * bridge/break RCLK signal and external Xi2sCDCLK pin.
 | 
			
		||||
 */
 | 
			
		||||
#define S3C_FEATURE_CDCLKCON	(1 << 0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct s3c_i2sv2_info - S3C I2S-V2 information
 | 
			
		||||
 * @dev: The parent device passed to use from the probe.
 | 
			
		||||
 * @regs: The pointer to the device registe block.
 | 
			
		||||
 * @feature: Set of bit-flags indicating features of the controller.
 | 
			
		||||
 * @master: True if the I2S core is the I2S bit clock master.
 | 
			
		||||
 * @dma_playback: DMA information for playback channel.
 | 
			
		||||
 * @dma_capture: DMA information for capture channel.
 | 
			
		||||
 * @suspend_iismod: PM save for the IISMOD register.
 | 
			
		||||
 * @suspend_iiscon: PM save for the IISCON register.
 | 
			
		||||
 * @suspend_iispsr: PM save for the IISPSR register.
 | 
			
		||||
 *
 | 
			
		||||
 * This is the private codec state for the hardware associated with an
 | 
			
		||||
 * I2S channel such as the register mappings and clock sources.
 | 
			
		||||
 */
 | 
			
		||||
struct s3c_i2sv2_info {
 | 
			
		||||
	struct device	*dev;
 | 
			
		||||
	void __iomem	*regs;
 | 
			
		||||
 | 
			
		||||
	u32		feature;
 | 
			
		||||
 | 
			
		||||
	struct clk	*iis_pclk;
 | 
			
		||||
	struct clk	*iis_cclk;
 | 
			
		||||
 | 
			
		||||
	unsigned char	 master;
 | 
			
		||||
 | 
			
		||||
	struct snd_dmaengine_dai_dma_data *dma_playback;
 | 
			
		||||
	struct snd_dmaengine_dai_dma_data *dma_capture;
 | 
			
		||||
 | 
			
		||||
	u32		 suspend_iismod;
 | 
			
		||||
	u32		 suspend_iiscon;
 | 
			
		||||
	u32		 suspend_iispsr;
 | 
			
		||||
 | 
			
		||||
	unsigned long	base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
 | 
			
		||||
 | 
			
		||||
struct s3c_i2sv2_rate_calc {
 | 
			
		||||
	unsigned int	clk_div;	/* for prescaler */
 | 
			
		||||
	unsigned int	fs_div;		/* for root frame clock */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 | 
			
		||||
				   unsigned int *fstab,
 | 
			
		||||
				   unsigned int rate, struct clk *clk);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * s3c_i2sv2_probe - probe for i2s device helper
 | 
			
		||||
 * @dai: The ASoC DAI structure supplied to the original probe.
 | 
			
		||||
 * @i2s: Our local i2s structure to fill in.
 | 
			
		||||
 * @base: The base address for the registers.
 | 
			
		||||
 */
 | 
			
		||||
extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
 | 
			
		||||
			   struct s3c_i2sv2_info *i2s);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * s3c_i2sv2_cleanup - cleanup resources allocated in s3c_i2sv2_probe
 | 
			
		||||
 * @dai: The ASoC DAI structure supplied to the original probe.
 | 
			
		||||
 * @i2s: Our local i2s structure to fill in.
 | 
			
		||||
 */
 | 
			
		||||
extern void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
 | 
			
		||||
			      struct s3c_i2sv2_info *i2s);
 | 
			
		||||
/**
 | 
			
		||||
 * s3c_i2sv2_register_component - register component and dai with soc core
 | 
			
		||||
 * @dev: DAI device
 | 
			
		||||
 * @id: DAI ID
 | 
			
		||||
 * @drv: The driver structure to register
 | 
			
		||||
 *
 | 
			
		||||
 * Fill in any missing fields and then register the given dai with the
 | 
			
		||||
 * soc core.
 | 
			
		||||
 */
 | 
			
		||||
extern int s3c_i2sv2_register_component(struct device *dev, int id,
 | 
			
		||||
					const struct snd_soc_component_driver *cmp_drv,
 | 
			
		||||
					struct snd_soc_dai_driver *dai_drv);
 | 
			
		||||
 | 
			
		||||
#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,251 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// ALSA Soc Audio Layer - S3C2412 I2S driver
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2006 Wolfson Microelectronics PLC.
 | 
			
		||||
//	Graeme Gregory graeme.gregory@wolfsonmicro.com
 | 
			
		||||
//	linux@wolfsonmicro.com
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2007, 2004-2005 Simtec Electronics
 | 
			
		||||
//	http://armlinux.simtec.co.uk/
 | 
			
		||||
//	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/pcm_params.h>
 | 
			
		||||
 | 
			
		||||
#include "dma.h"
 | 
			
		||||
#include "regs-i2s-v2.h"
 | 
			
		||||
#include "s3c2412-i2s.h"
 | 
			
		||||
 | 
			
		||||
#include <linux/platform_data/asoc-s3c.h>
 | 
			
		||||
 | 
			
		||||
static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = {
 | 
			
		||||
	.chan_name	= "tx",
 | 
			
		||||
	.addr_width	= 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = {
 | 
			
		||||
	.chan_name	= "rx",
 | 
			
		||||
	.addr_width	= 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct s3c_i2sv2_info s3c2412_i2s;
 | 
			
		||||
 | 
			
		||||
static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	snd_soc_dai_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out,
 | 
			
		||||
					&s3c2412_i2s_pcm_stereo_in);
 | 
			
		||||
 | 
			
		||||
	ret = s3c_i2sv2_probe(dai, &s3c2412_i2s);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
 | 
			
		||||
	s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
 | 
			
		||||
 | 
			
		||||
	s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk");
 | 
			
		||||
	if (IS_ERR(s3c2412_i2s.iis_cclk)) {
 | 
			
		||||
		pr_err("failed to get i2sclk clock\n");
 | 
			
		||||
		ret = PTR_ERR(s3c2412_i2s.iis_cclk);
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set MPLL as the source for IIS CLK */
 | 
			
		||||
 | 
			
		||||
	clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
 | 
			
		||||
	ret = clk_prepare_enable(s3c2412_i2s.iis_cclk);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	clk_disable_unprepare(s3c2412_i2s.iis_cclk);
 | 
			
		||||
	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				 struct snd_pcm_hw_params *params,
 | 
			
		||||
				 struct snd_soc_dai *cpu_dai)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	pr_debug("Entered %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	switch (params_width(params)) {
 | 
			
		||||
	case 8:
 | 
			
		||||
		iismod |= S3C2412_IISMOD_8BIT;
 | 
			
		||||
		break;
 | 
			
		||||
	case 16:
 | 
			
		||||
		iismod &= ~S3C2412_IISMOD_8BIT;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
	pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int s3c2412_i2s_suspend(struct snd_soc_component *component)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	if (component->active) {
 | 
			
		||||
		i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
		i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
 | 
			
		||||
		i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
 | 
			
		||||
 | 
			
		||||
		/* some basic suspend checks */
 | 
			
		||||
 | 
			
		||||
		iismod = readl(i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
 | 
			
		||||
		if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
 | 
			
		||||
			pr_warn("%s: RXDMA active?\n", __func__);
 | 
			
		||||
 | 
			
		||||
		if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
 | 
			
		||||
			pr_warn("%s: TXDMA active?\n", __func__);
 | 
			
		||||
 | 
			
		||||
		if (iismod & S3C2412_IISCON_IIS_ACTIVE)
 | 
			
		||||
			pr_warn("%s: IIS active\n", __func__);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c2412_i2s_resume(struct snd_soc_component *component)
 | 
			
		||||
{
 | 
			
		||||
	struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
 | 
			
		||||
 | 
			
		||||
	pr_info("component_active %d, IISMOD %08x, IISCON %08x\n",
 | 
			
		||||
		component->active, i2s->suspend_iismod, i2s->suspend_iiscon);
 | 
			
		||||
 | 
			
		||||
	if (component->active) {
 | 
			
		||||
		writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
 | 
			
		||||
		writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
 | 
			
		||||
		writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
 | 
			
		||||
 | 
			
		||||
		writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
 | 
			
		||||
		       i2s->regs + S3C2412_IISFIC);
 | 
			
		||||
 | 
			
		||||
		ndelay(250);
 | 
			
		||||
		writel(0x0, i2s->regs + S3C2412_IISFIC);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define s3c2412_i2s_suspend NULL
 | 
			
		||||
#define s3c2412_i2s_resume  NULL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define S3C2412_I2S_RATES \
 | 
			
		||||
	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
 | 
			
		||||
	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
 | 
			
		||||
	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
 | 
			
		||||
	.hw_params	= s3c2412_i2s_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_driver s3c2412_i2s_dai = {
 | 
			
		||||
	.probe		= s3c2412_i2s_probe,
 | 
			
		||||
	.remove	= s3c2412_i2s_remove,
 | 
			
		||||
	.playback = {
 | 
			
		||||
		.channels_min	= 2,
 | 
			
		||||
		.channels_max	= 2,
 | 
			
		||||
		.rates		= S3C2412_I2S_RATES,
 | 
			
		||||
		.formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
 | 
			
		||||
	},
 | 
			
		||||
	.capture = {
 | 
			
		||||
		.channels_min	= 2,
 | 
			
		||||
		.channels_max	= 2,
 | 
			
		||||
		.rates		= S3C2412_I2S_RATES,
 | 
			
		||||
		.formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
 | 
			
		||||
	},
 | 
			
		||||
	.ops = &s3c2412_i2s_dai_ops,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_component_driver s3c2412_i2s_component = {
 | 
			
		||||
	.name			= "s3c2412-i2s",
 | 
			
		||||
	.suspend		= s3c2412_i2s_suspend,
 | 
			
		||||
	.resume			= s3c2412_i2s_resume,
 | 
			
		||||
	.legacy_dai_naming	= 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
 | 
			
		||||
 | 
			
		||||
	if (!pdata) {
 | 
			
		||||
		dev_err(&pdev->dev, "missing platform data");
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s3c2412_i2s.regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 | 
			
		||||
	if (IS_ERR(s3c2412_i2s.regs))
 | 
			
		||||
		return PTR_ERR(s3c2412_i2s.regs);
 | 
			
		||||
 | 
			
		||||
	s3c2412_i2s_pcm_stereo_out.addr = res->start + S3C2412_IISTXD;
 | 
			
		||||
	s3c2412_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
 | 
			
		||||
	s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD;
 | 
			
		||||
	s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
 | 
			
		||||
 | 
			
		||||
	ret = samsung_asoc_dma_platform_register(&pdev->dev,
 | 
			
		||||
						 pdata->dma_filter,
 | 
			
		||||
						 "tx", "rx", NULL);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("failed to register the DMA: %d\n", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = s3c_i2sv2_register_component(&pdev->dev, -1,
 | 
			
		||||
					   &s3c2412_i2s_component,
 | 
			
		||||
					   &s3c2412_i2s_dai);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		pr_err("failed to register the dai\n");
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver s3c2412_iis_driver = {
 | 
			
		||||
	.probe  = s3c2412_iis_dev_probe,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "s3c2412-iis",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(s3c2412_iis_driver);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("platform:s3c2412-iis");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
			
		||||
/*
 | 
			
		||||
 * ALSA Soc Audio Layer - S3C2412 I2S driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2007 Simtec Electronics
 | 
			
		||||
 *	http://armlinux.simtec.co.uk/
 | 
			
		||||
 *	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
 | 
			
		||||
#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
 | 
			
		||||
 | 
			
		||||
#include "s3c-i2s-v2.h"
 | 
			
		||||
 | 
			
		||||
#define S3C2412_DIV_BCLK	S3C_I2SV2_DIV_BCLK
 | 
			
		||||
#define S3C2412_DIV_RCLK	S3C_I2SV2_DIV_RCLK
 | 
			
		||||
#define S3C2412_DIV_PRESCALER	S3C_I2SV2_DIV_PRESCALER
 | 
			
		||||
 | 
			
		||||
#define S3C2412_CLKSRC_PCLK	S3C_I2SV2_CLKSRC_PCLK
 | 
			
		||||
#define S3C2412_CLKSRC_I2SCLK	S3C_I2SV2_CLKSRC_AUDIOBUS
 | 
			
		||||
 | 
			
		||||
#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,463 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// s3c24xx-i2s.c  --  ALSA Soc Audio Layer
 | 
			
		||||
//
 | 
			
		||||
// (c) 2006 Wolfson Microelectronics PLC.
 | 
			
		||||
// Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2004-2005 Simtec Electronics
 | 
			
		||||
//	http://armlinux.simtec.co.uk/
 | 
			
		||||
//	Ben Dooks <ben@simtec.co.uk>
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/pcm_params.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-iis.h"
 | 
			
		||||
#include "dma.h"
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
 | 
			
		||||
static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
 | 
			
		||||
	.chan_name	= "tx",
 | 
			
		||||
	.addr_width	= 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = {
 | 
			
		||||
	.chan_name	= "rx",
 | 
			
		||||
	.addr_width	= 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct s3c24xx_i2s_info {
 | 
			
		||||
	void __iomem	*regs;
 | 
			
		||||
	struct clk	*iis_clk;
 | 
			
		||||
	u32		iiscon;
 | 
			
		||||
	u32		iismod;
 | 
			
		||||
	u32		iisfcon;
 | 
			
		||||
	u32		iispsr;
 | 
			
		||||
};
 | 
			
		||||
static struct s3c24xx_i2s_info s3c24xx_i2s;
 | 
			
		||||
 | 
			
		||||
static void s3c24xx_snd_txctrl(int on)
 | 
			
		||||
{
 | 
			
		||||
	u32 iisfcon;
 | 
			
		||||
	u32 iiscon;
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
 | 
			
		||||
	pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 | 
			
		||||
 | 
			
		||||
	if (on) {
 | 
			
		||||
		iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
 | 
			
		||||
		iiscon  |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
 | 
			
		||||
		iiscon  &= ~S3C2410_IISCON_TXIDLE;
 | 
			
		||||
		iismod  |= S3C2410_IISMOD_TXMODE;
 | 
			
		||||
 | 
			
		||||
		writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
		writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
		writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* note, we have to disable the FIFOs otherwise bad things
 | 
			
		||||
		 * seem to happen when the DMA stops. According to the
 | 
			
		||||
		 * Samsung supplied kernel, this should allow the DMA
 | 
			
		||||
		 * engine and FIFOs to reset. If this isn't allowed, the
 | 
			
		||||
		 * DMA engine will simply freeze randomly.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		iisfcon &= ~S3C2410_IISFCON_TXENABLE;
 | 
			
		||||
		iisfcon &= ~S3C2410_IISFCON_TXDMA;
 | 
			
		||||
		iiscon  |=  S3C2410_IISCON_TXIDLE;
 | 
			
		||||
		iiscon  &= ~S3C2410_IISCON_TXDMAEN;
 | 
			
		||||
		iismod  &= ~S3C2410_IISMOD_TXMODE;
 | 
			
		||||
 | 
			
		||||
		writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
		writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
		writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void s3c24xx_snd_rxctrl(int on)
 | 
			
		||||
{
 | 
			
		||||
	u32 iisfcon;
 | 
			
		||||
	u32 iiscon;
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
 | 
			
		||||
	pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 | 
			
		||||
 | 
			
		||||
	if (on) {
 | 
			
		||||
		iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
 | 
			
		||||
		iiscon  |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
 | 
			
		||||
		iiscon  &= ~S3C2410_IISCON_RXIDLE;
 | 
			
		||||
		iismod  |= S3C2410_IISMOD_RXMODE;
 | 
			
		||||
 | 
			
		||||
		writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
		writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
		writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* note, we have to disable the FIFOs otherwise bad things
 | 
			
		||||
		 * seem to happen when the DMA stops. According to the
 | 
			
		||||
		 * Samsung supplied kernel, this should allow the DMA
 | 
			
		||||
		 * engine and FIFOs to reset. If this isn't allowed, the
 | 
			
		||||
		 * DMA engine will simply freeze randomly.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		iisfcon &= ~S3C2410_IISFCON_RXENABLE;
 | 
			
		||||
		iisfcon &= ~S3C2410_IISFCON_RXDMA;
 | 
			
		||||
		iiscon  |= S3C2410_IISCON_RXIDLE;
 | 
			
		||||
		iiscon  &= ~S3C2410_IISCON_RXDMAEN;
 | 
			
		||||
		iismod  &= ~S3C2410_IISMOD_RXMODE;
 | 
			
		||||
 | 
			
		||||
		writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
		writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
		writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Wait for the LR signal to allow synchronisation to the L/R clock
 | 
			
		||||
 * from the codec. May only be needed for slave mode.
 | 
			
		||||
 */
 | 
			
		||||
static int s3c24xx_snd_lrsync(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 iiscon;
 | 
			
		||||
	int timeout = 50; /* 5ms */
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
		if (iiscon & S3C2410_IISCON_LRINDEX)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (!timeout--)
 | 
			
		||||
			return -ETIMEDOUT;
 | 
			
		||||
		udelay(100);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check whether CPU is the master or slave
 | 
			
		||||
 */
 | 
			
		||||
static inline int s3c24xx_snd_is_clkmaster(void)
 | 
			
		||||
{
 | 
			
		||||
	return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set S3C24xx I2S DAI format
 | 
			
		||||
 */
 | 
			
		||||
static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
		unsigned int fmt)
 | 
			
		||||
{
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	pr_debug("hw_params r: IISMOD: %x \n", iismod);
 | 
			
		||||
 | 
			
		||||
	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
 | 
			
		||||
	case SND_SOC_DAIFMT_BC_FC:
 | 
			
		||||
		iismod |= S3C2410_IISMOD_SLAVE;
 | 
			
		||||
		break;
 | 
			
		||||
	case SND_SOC_DAIFMT_BP_FP:
 | 
			
		||||
		iismod &= ~S3C2410_IISMOD_SLAVE;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 | 
			
		||||
	case SND_SOC_DAIFMT_LEFT_J:
 | 
			
		||||
		iismod |= S3C2410_IISMOD_MSB;
 | 
			
		||||
		break;
 | 
			
		||||
	case SND_SOC_DAIFMT_I2S:
 | 
			
		||||
		iismod &= ~S3C2410_IISMOD_MSB;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	pr_debug("hw_params w: IISMOD: %x \n", iismod);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
				 struct snd_pcm_hw_params *params,
 | 
			
		||||
				 struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_dmaengine_dai_dma_data *dma_data;
 | 
			
		||||
	u32 iismod;
 | 
			
		||||
 | 
			
		||||
	dma_data = snd_soc_dai_get_dma_data(dai, substream);
 | 
			
		||||
 | 
			
		||||
	/* Working copies of register */
 | 
			
		||||
	iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	pr_debug("hw_params r: IISMOD: %x\n", iismod);
 | 
			
		||||
 | 
			
		||||
	switch (params_width(params)) {
 | 
			
		||||
	case 8:
 | 
			
		||||
		iismod &= ~S3C2410_IISMOD_16BIT;
 | 
			
		||||
		dma_data->addr_width = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case 16:
 | 
			
		||||
		iismod |= S3C2410_IISMOD_16BIT;
 | 
			
		||||
		dma_data->addr_width = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	pr_debug("hw_params w: IISMOD: %x\n", iismod);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 | 
			
		||||
			       struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_START:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_RESUME:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 | 
			
		||||
		if (!s3c24xx_snd_is_clkmaster()) {
 | 
			
		||||
			ret = s3c24xx_snd_lrsync();
 | 
			
		||||
			if (ret)
 | 
			
		||||
				goto exit_err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 | 
			
		||||
			s3c24xx_snd_rxctrl(1);
 | 
			
		||||
		else
 | 
			
		||||
			s3c24xx_snd_txctrl(1);
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_STOP:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_SUSPEND:
 | 
			
		||||
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 | 
			
		||||
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 | 
			
		||||
			s3c24xx_snd_rxctrl(0);
 | 
			
		||||
		else
 | 
			
		||||
			s3c24xx_snd_txctrl(0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
exit_err:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set S3C24xx Clock source
 | 
			
		||||
 */
 | 
			
		||||
static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
	int clk_id, unsigned int freq, int dir)
 | 
			
		||||
{
 | 
			
		||||
	u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
 | 
			
		||||
	iismod &= ~S3C2440_IISMOD_MPLL;
 | 
			
		||||
 | 
			
		||||
	switch (clk_id) {
 | 
			
		||||
	case S3C24XX_CLKSRC_PCLK:
 | 
			
		||||
		break;
 | 
			
		||||
	case S3C24XX_CLKSRC_MPLL:
 | 
			
		||||
		iismod |= S3C2440_IISMOD_MPLL;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set S3C24xx Clock dividers
 | 
			
		||||
 */
 | 
			
		||||
static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
 | 
			
		||||
	int div_id, int div)
 | 
			
		||||
{
 | 
			
		||||
	u32 reg;
 | 
			
		||||
 | 
			
		||||
	switch (div_id) {
 | 
			
		||||
	case S3C24XX_DIV_BCLK:
 | 
			
		||||
		reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
 | 
			
		||||
		writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
		break;
 | 
			
		||||
	case S3C24XX_DIV_MCLK:
 | 
			
		||||
		reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
 | 
			
		||||
		writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
		break;
 | 
			
		||||
	case S3C24XX_DIV_PRESCALER:
 | 
			
		||||
		writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
 | 
			
		||||
		reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
		writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * To avoid duplicating clock code, allow machine driver to
 | 
			
		||||
 * get the clockrate from here.
 | 
			
		||||
 */
 | 
			
		||||
u32 s3c24xx_i2s_get_clockrate(void)
 | 
			
		||||
{
 | 
			
		||||
	return clk_get_rate(s3c24xx_i2s.iis_clk);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
 | 
			
		||||
					&s3c24xx_i2s_pcm_stereo_in);
 | 
			
		||||
 | 
			
		||||
	s3c24xx_i2s.iis_clk = devm_clk_get(dai->dev, "iis");
 | 
			
		||||
	if (IS_ERR(s3c24xx_i2s.iis_clk)) {
 | 
			
		||||
		pr_err("failed to get iis_clock\n");
 | 
			
		||||
		return PTR_ERR(s3c24xx_i2s.iis_clk);
 | 
			
		||||
	}
 | 
			
		||||
	ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
 | 
			
		||||
	s3c24xx_snd_txctrl(0);
 | 
			
		||||
	s3c24xx_snd_rxctrl(0);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int s3c24xx_i2s_suspend(struct snd_soc_component *component)
 | 
			
		||||
{
 | 
			
		||||
	s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
	s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
 | 
			
		||||
 | 
			
		||||
	clk_disable_unprepare(s3c24xx_i2s.iis_clk);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_i2s_resume(struct snd_soc_component *component)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
 | 
			
		||||
	writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
 | 
			
		||||
	writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
 | 
			
		||||
	writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define s3c24xx_i2s_suspend NULL
 | 
			
		||||
#define s3c24xx_i2s_resume NULL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define S3C24XX_I2S_RATES \
 | 
			
		||||
	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
 | 
			
		||||
	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
 | 
			
		||||
	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
 | 
			
		||||
	.trigger	= s3c24xx_i2s_trigger,
 | 
			
		||||
	.hw_params	= s3c24xx_i2s_hw_params,
 | 
			
		||||
	.set_fmt	= s3c24xx_i2s_set_fmt,
 | 
			
		||||
	.set_clkdiv	= s3c24xx_i2s_set_clkdiv,
 | 
			
		||||
	.set_sysclk	= s3c24xx_i2s_set_sysclk,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
 | 
			
		||||
	.probe = s3c24xx_i2s_probe,
 | 
			
		||||
	.playback = {
 | 
			
		||||
		.channels_min = 2,
 | 
			
		||||
		.channels_max = 2,
 | 
			
		||||
		.rates = S3C24XX_I2S_RATES,
 | 
			
		||||
		.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
 | 
			
		||||
	.capture = {
 | 
			
		||||
		.channels_min = 2,
 | 
			
		||||
		.channels_max = 2,
 | 
			
		||||
		.rates = S3C24XX_I2S_RATES,
 | 
			
		||||
		.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
 | 
			
		||||
	.ops = &s3c24xx_i2s_dai_ops,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_component_driver s3c24xx_i2s_component = {
 | 
			
		||||
	.name			= "s3c24xx-i2s",
 | 
			
		||||
	.suspend		= s3c24xx_i2s_suspend,
 | 
			
		||||
	.resume			= s3c24xx_i2s_resume,
 | 
			
		||||
	.legacy_dai_naming	= 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	s3c24xx_i2s.regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 | 
			
		||||
	if (IS_ERR(s3c24xx_i2s.regs))
 | 
			
		||||
		return PTR_ERR(s3c24xx_i2s.regs);
 | 
			
		||||
 | 
			
		||||
	s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO;
 | 
			
		||||
	s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
 | 
			
		||||
 | 
			
		||||
	ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL,
 | 
			
		||||
						 "tx", "rx", NULL);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = devm_snd_soc_register_component(&pdev->dev,
 | 
			
		||||
			&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to register the DAI\n");
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver s3c24xx_iis_driver = {
 | 
			
		||||
	.probe  = s3c24xx_iis_dev_probe,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "s3c24xx-iis",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(s3c24xx_iis_driver);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("platform:s3c24xx-iis");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
			
		||||
/*
 | 
			
		||||
 * s3c24xx-i2s.c  --  ALSA Soc Audio Layer
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2005 Wolfson Microelectronics PLC.
 | 
			
		||||
 * Author: Graeme Gregory
 | 
			
		||||
 *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
 | 
			
		||||
 *
 | 
			
		||||
 *  Revision history
 | 
			
		||||
 *    10th Nov 2006   Initial version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef S3C24XXI2S_H_
 | 
			
		||||
#define S3C24XXI2S_H_
 | 
			
		||||
 | 
			
		||||
/* clock sources */
 | 
			
		||||
#define S3C24XX_CLKSRC_PCLK 0
 | 
			
		||||
#define S3C24XX_CLKSRC_MPLL 1
 | 
			
		||||
 | 
			
		||||
/* Clock dividers */
 | 
			
		||||
#define S3C24XX_DIV_MCLK	0
 | 
			
		||||
#define S3C24XX_DIV_BCLK	1
 | 
			
		||||
#define S3C24XX_DIV_PRESCALER	2
 | 
			
		||||
 | 
			
		||||
/* prescaler */
 | 
			
		||||
#define S3C24XX_PRESCALE(a,b) \
 | 
			
		||||
	(((a - 1) << S3C2410_IISPSR_INTSHIFT) | ((b - 1) << S3C2410_IISPSR_EXTSHFIT))
 | 
			
		||||
 | 
			
		||||
u32 s3c24xx_i2s_get_clockrate(void);
 | 
			
		||||
 | 
			
		||||
#endif /*S3C24XXI2S_H_*/
 | 
			
		||||
| 
						 | 
				
			
			@ -1,372 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2009 Simtec Electronics
 | 
			
		||||
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/platform_data/asoc-s3c24xx_simtec.h>
 | 
			
		||||
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
#include "s3c24xx_simtec.h"
 | 
			
		||||
 | 
			
		||||
static struct s3c24xx_audio_simtec_pdata *pdata;
 | 
			
		||||
static struct clk *xtal_clk;
 | 
			
		||||
 | 
			
		||||
static int spk_gain;
 | 
			
		||||
static int spk_unmute;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * speaker_gain_get - read the speaker gain setting.
 | 
			
		||||
 * @kcontrol: The control for the speaker gain.
 | 
			
		||||
 * @ucontrol: The value that needs to be updated.
 | 
			
		||||
 *
 | 
			
		||||
 * Read the value for the AMP gain control.
 | 
			
		||||
 */
 | 
			
		||||
static int speaker_gain_get(struct snd_kcontrol *kcontrol,
 | 
			
		||||
			    struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	ucontrol->value.integer.value[0] = spk_gain;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * speaker_gain_set - set the value of the speaker amp gain
 | 
			
		||||
 * @value: The value to write.
 | 
			
		||||
 */
 | 
			
		||||
static void speaker_gain_set(int value)
 | 
			
		||||
{
 | 
			
		||||
	gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
 | 
			
		||||
	gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * speaker_gain_put - set the speaker gain setting.
 | 
			
		||||
 * @kcontrol: The control for the speaker gain.
 | 
			
		||||
 * @ucontrol: The value that needs to be set.
 | 
			
		||||
 *
 | 
			
		||||
 * Set the value of the speaker gain from the specified
 | 
			
		||||
 * @ucontrol setting.
 | 
			
		||||
 *
 | 
			
		||||
 * Note, if the speaker amp is muted, then we do not set a gain value
 | 
			
		||||
 * as at-least one of the ICs that is fitted will try and power up even
 | 
			
		||||
 * if the main control is set to off.
 | 
			
		||||
 */
 | 
			
		||||
static int speaker_gain_put(struct snd_kcontrol *kcontrol,
 | 
			
		||||
			    struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	int value = ucontrol->value.integer.value[0];
 | 
			
		||||
 | 
			
		||||
	spk_gain = value;
 | 
			
		||||
 | 
			
		||||
	if (!spk_unmute)
 | 
			
		||||
		speaker_gain_set(value);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_kcontrol_new amp_gain_controls[] = {
 | 
			
		||||
	SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
 | 
			
		||||
		       speaker_gain_get, speaker_gain_put),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * spk_unmute_state - set the unmute state of the speaker
 | 
			
		||||
 * @to: zero to unmute, non-zero to ununmute.
 | 
			
		||||
 */
 | 
			
		||||
static void spk_unmute_state(int to)
 | 
			
		||||
{
 | 
			
		||||
	pr_debug("%s: to=%d\n", __func__, to);
 | 
			
		||||
 | 
			
		||||
	spk_unmute = to;
 | 
			
		||||
	gpio_set_value(pdata->amp_gpio, to);
 | 
			
		||||
 | 
			
		||||
	/* if we're umuting, also re-set the gain */
 | 
			
		||||
	if (to && pdata->amp_gain[0] > 0)
 | 
			
		||||
		speaker_gain_set(spk_gain);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * speaker_unmute_get - read the speaker unmute setting.
 | 
			
		||||
 * @kcontrol: The control for the speaker gain.
 | 
			
		||||
 * @ucontrol: The value that needs to be updated.
 | 
			
		||||
 *
 | 
			
		||||
 * Read the value for the AMP gain control.
 | 
			
		||||
 */
 | 
			
		||||
static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
 | 
			
		||||
			    struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	ucontrol->value.integer.value[0] = spk_unmute;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * speaker_unmute_put - set the speaker unmute setting.
 | 
			
		||||
 * @kcontrol: The control for the speaker gain.
 | 
			
		||||
 * @ucontrol: The value that needs to be set.
 | 
			
		||||
 *
 | 
			
		||||
 * Set the value of the speaker gain from the specified
 | 
			
		||||
 * @ucontrol setting.
 | 
			
		||||
 */
 | 
			
		||||
static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
 | 
			
		||||
			    struct snd_ctl_elem_value *ucontrol)
 | 
			
		||||
{
 | 
			
		||||
	spk_unmute_state(ucontrol->value.integer.value[0]);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This is added as a manual control as the speaker amps create clicks
 | 
			
		||||
 * when their power state is changed, which are far more noticeable than
 | 
			
		||||
 * anything produced by the CODEC itself.
 | 
			
		||||
 */
 | 
			
		||||
static const struct snd_kcontrol_new amp_unmute_controls[] = {
 | 
			
		||||
	SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
 | 
			
		||||
		       speaker_unmute_get, speaker_unmute_put),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_card *card = rtd->card;
 | 
			
		||||
 | 
			
		||||
	if (pdata->amp_gpio > 0) {
 | 
			
		||||
		pr_debug("%s: adding amp routes\n", __func__);
 | 
			
		||||
 | 
			
		||||
		snd_soc_add_card_controls(card, amp_unmute_controls,
 | 
			
		||||
				     ARRAY_SIZE(amp_unmute_controls));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pdata->amp_gain[0] > 0) {
 | 
			
		||||
		pr_debug("%s: adding amp controls\n", __func__);
 | 
			
		||||
		snd_soc_add_card_controls(card, amp_gain_controls,
 | 
			
		||||
				     ARRAY_SIZE(amp_gain_controls));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(simtec_audio_init);
 | 
			
		||||
 | 
			
		||||
#define CODEC_CLOCK 12000000
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * simtec_hw_params - update hardware parameters
 | 
			
		||||
 * @substream: The audio substream instance.
 | 
			
		||||
 * @params: The parameters requested.
 | 
			
		||||
 *
 | 
			
		||||
 * Update the codec data routing and configuration  settings
 | 
			
		||||
 * from the supplied data.
 | 
			
		||||
 */
 | 
			
		||||
static int simtec_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
			    struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
 | 
			
		||||
				     CODEC_CLOCK, SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err( "%s: failed setting codec sysclk\n", __func__);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pdata->use_mpllin) {
 | 
			
		||||
		ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
 | 
			
		||||
					     0, SND_SOC_CLOCK_OUT);
 | 
			
		||||
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			pr_err("%s: failed to set MPLLin as clksrc\n",
 | 
			
		||||
			       __func__);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pdata->output_cdclk) {
 | 
			
		||||
		int cdclk_scale;
 | 
			
		||||
 | 
			
		||||
		cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
 | 
			
		||||
		cdclk_scale--;
 | 
			
		||||
 | 
			
		||||
		ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 | 
			
		||||
					     cdclk_scale);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			pr_err("%s: failed to set clock div\n",
 | 
			
		||||
			       __func__);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
 | 
			
		||||
{
 | 
			
		||||
	/* call any board supplied startup code, this currently only
 | 
			
		||||
	 * covers the bast/vr1000 which have a CPLD in the way of the
 | 
			
		||||
	 * LRCLK */
 | 
			
		||||
	if (pd->startup)
 | 
			
		||||
		pd->startup();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops simtec_snd_ops = {
 | 
			
		||||
	.hw_params	= simtec_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * attach_gpio_amp - get and configure the necessary gpios
 | 
			
		||||
 * @dev: The device we're probing.
 | 
			
		||||
 * @pd: The platform data supplied by the board.
 | 
			
		||||
 *
 | 
			
		||||
 * If there is a GPIO based amplifier attached to the board, claim
 | 
			
		||||
 * the necessary GPIO lines for it, and set default values.
 | 
			
		||||
 */
 | 
			
		||||
static int attach_gpio_amp(struct device *dev,
 | 
			
		||||
			   struct s3c24xx_audio_simtec_pdata *pd)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* attach gpio amp gain (if any) */
 | 
			
		||||
	if (pdata->amp_gain[0] > 0) {
 | 
			
		||||
		ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(dev, "cannot get amp gpio gain0\n");
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(dev, "cannot get amp gpio gain1\n");
 | 
			
		||||
			gpio_free(pdata->amp_gain[0]);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		gpio_direction_output(pd->amp_gain[0], 0);
 | 
			
		||||
		gpio_direction_output(pd->amp_gain[1], 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* note, currently we assume GPA0 isn't valid amp */
 | 
			
		||||
	if (pdata->amp_gpio > 0) {
 | 
			
		||||
		ret = gpio_request(pd->amp_gpio, "gpio-amp");
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(dev, "cannot get amp gpio %d (%d)\n",
 | 
			
		||||
				pd->amp_gpio, ret);
 | 
			
		||||
			goto err_amp;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* set the amp off at startup */
 | 
			
		||||
		spk_unmute_state(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_amp:
 | 
			
		||||
	if (pd->amp_gain[0] > 0) {
 | 
			
		||||
		gpio_free(pd->amp_gain[0]);
 | 
			
		||||
		gpio_free(pd->amp_gain[1]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
 | 
			
		||||
{
 | 
			
		||||
	if (pd->amp_gain[0] > 0) {
 | 
			
		||||
		gpio_free(pd->amp_gain[0]);
 | 
			
		||||
		gpio_free(pd->amp_gain[1]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pd->amp_gpio > 0)
 | 
			
		||||
		gpio_free(pd->amp_gpio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int simtec_audio_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	simtec_call_startup(pdata);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct dev_pm_ops simtec_audio_pmops = {
 | 
			
		||||
	.resume	= simtec_audio_resume,
 | 
			
		||||
};
 | 
			
		||||
EXPORT_SYMBOL_GPL(simtec_audio_pmops);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int simtec_audio_core_probe(struct platform_device *pdev,
 | 
			
		||||
			    struct snd_soc_card *card)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *snd_dev;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	card->dai_link->ops = &simtec_snd_ops;
 | 
			
		||||
	card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
				  SND_SOC_DAIFMT_CBM_CFM;
 | 
			
		||||
 | 
			
		||||
	pdata = pdev->dev.platform_data;
 | 
			
		||||
	if (!pdata) {
 | 
			
		||||
		dev_err(&pdev->dev, "no platform data supplied\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	simtec_call_startup(pdata);
 | 
			
		||||
 | 
			
		||||
	xtal_clk = clk_get(&pdev->dev, "xtal");
 | 
			
		||||
	if (IS_ERR(xtal_clk)) {
 | 
			
		||||
		dev_err(&pdev->dev, "could not get clkout0\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
 | 
			
		||||
 | 
			
		||||
	ret = attach_gpio_amp(&pdev->dev, pdata);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err_clk;
 | 
			
		||||
 | 
			
		||||
	snd_dev = platform_device_alloc("soc-audio", -1);
 | 
			
		||||
	if (!snd_dev) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to alloc soc-audio device\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto err_gpio;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(snd_dev, card);
 | 
			
		||||
 | 
			
		||||
	ret = platform_device_add(snd_dev);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to add soc-audio dev\n");
 | 
			
		||||
		goto err_pdev;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, snd_dev);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_pdev:
 | 
			
		||||
	platform_device_put(snd_dev);
 | 
			
		||||
 | 
			
		||||
err_gpio:
 | 
			
		||||
	detach_gpio_amp(pdata);
 | 
			
		||||
 | 
			
		||||
err_clk:
 | 
			
		||||
	clk_put(xtal_clk);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
 | 
			
		||||
 | 
			
		||||
int simtec_audio_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *snd_dev = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	platform_device_unregister(snd_dev);
 | 
			
		||||
 | 
			
		||||
	detach_gpio_amp(pdata);
 | 
			
		||||
	clk_put(xtal_clk);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(simtec_audio_remove);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2009 Simtec Electronics
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
 | 
			
		||||
 | 
			
		||||
extern int simtec_audio_core_probe(struct platform_device *pdev,
 | 
			
		||||
				   struct snd_soc_card *card);
 | 
			
		||||
 | 
			
		||||
extern int simtec_audio_remove(struct platform_device *pdev);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
extern const struct dev_pm_ops simtec_audio_pmops;
 | 
			
		||||
#define simtec_audio_pm &simtec_audio_pmops
 | 
			
		||||
#else
 | 
			
		||||
#define simtec_audio_pm NULL
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,112 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2009 Simtec Electronics
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
 | 
			
		||||
#include "s3c24xx_simtec.h"
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_widget dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_LINE("GSM Out", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("GSM In", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("Line In", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("Line Out", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("ZV", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_route base_map[] = {
 | 
			
		||||
	/* Headphone connected to HP{L,R}OUT and HP{L,R}COM */
 | 
			
		||||
 | 
			
		||||
	{ "Headphone Jack", NULL, "HPLOUT" },
 | 
			
		||||
	{ "Headphone Jack", NULL, "HPLCOM" },
 | 
			
		||||
	{ "Headphone Jack", NULL, "HPROUT" },
 | 
			
		||||
	{ "Headphone Jack", NULL, "HPRCOM" },
 | 
			
		||||
 | 
			
		||||
	/* ZV connected to Line1 */
 | 
			
		||||
 | 
			
		||||
	{ "LINE1L", NULL, "ZV" },
 | 
			
		||||
	{ "LINE1R", NULL, "ZV" },
 | 
			
		||||
 | 
			
		||||
	/* Line In connected to Line2 */
 | 
			
		||||
 | 
			
		||||
	{ "LINE2L", NULL, "Line In" },
 | 
			
		||||
	{ "LINE2R", NULL, "Line In" },
 | 
			
		||||
 | 
			
		||||
	/* Microphone connected to MIC3R and MIC_BIAS */
 | 
			
		||||
 | 
			
		||||
	{ "MIC3L", NULL, "Mic Jack" },
 | 
			
		||||
 | 
			
		||||
	/* GSM connected to MONO_LOUT and MIC3L (in) */
 | 
			
		||||
 | 
			
		||||
	{ "GSM Out", NULL, "MONO_LOUT" },
 | 
			
		||||
	{ "MIC3L", NULL, "GSM In" },
 | 
			
		||||
 | 
			
		||||
	/* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are
 | 
			
		||||
	 * not using the DAPM to power it up and down as there it makes
 | 
			
		||||
	 * a click when powering up. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * simtec_hermes_init - initialise and add controls
 | 
			
		||||
 * @codec; The codec instance to attach to.
 | 
			
		||||
 *
 | 
			
		||||
 * Attach our controls and configure the necessary codec
 | 
			
		||||
 * mappings for our sound card instance.
 | 
			
		||||
*/
 | 
			
		||||
static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	simtec_audio_init(rtd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(tlv320aic33,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.0-001a",
 | 
			
		||||
				      "tlv320aic3x-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link simtec_dai_aic33 = {
 | 
			
		||||
	.name		= "tlv320aic33",
 | 
			
		||||
	.stream_name	= "TLV320AIC33",
 | 
			
		||||
	.init		= simtec_hermes_init,
 | 
			
		||||
	SND_SOC_DAILINK_REG(tlv320aic33),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* simtec audio machine driver */
 | 
			
		||||
static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
 | 
			
		||||
	.name		= "Simtec-Hermes",
 | 
			
		||||
	.owner		= THIS_MODULE,
 | 
			
		||||
	.dai_link	= &simtec_dai_aic33,
 | 
			
		||||
	.num_links	= 1,
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets	= dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
 | 
			
		||||
	.dapm_routes	= base_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(base_map),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int simtec_audio_hermes_probe(struct platform_device *pd)
 | 
			
		||||
{
 | 
			
		||||
	dev_info(&pd->dev, "probing....\n");
 | 
			
		||||
	return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver simtec_audio_hermes_platdrv = {
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.name	= "s3c24xx-simtec-hermes-snd",
 | 
			
		||||
		.pm	= simtec_audio_pm,
 | 
			
		||||
	},
 | 
			
		||||
	.probe	= simtec_audio_hermes_probe,
 | 
			
		||||
	.remove	= simtec_audio_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(simtec_audio_hermes_platdrv);
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,100 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2009 Simtec Electronics
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
 | 
			
		||||
#include "s3c24xx_simtec.h"
 | 
			
		||||
 | 
			
		||||
/* supported machines:
 | 
			
		||||
 *
 | 
			
		||||
 * Machine	Connections		AMP
 | 
			
		||||
 * -------	-----------		---
 | 
			
		||||
 * BAST		MIC, HPOUT, LOUT, LIN	TPA2001D1 (HPOUTL,R) (gain hardwired)
 | 
			
		||||
 * VR1000	HPOUT, LIN		None
 | 
			
		||||
 * VR2000	LIN, LOUT, MIC, HP	LM4871 (HPOUTL,R)
 | 
			
		||||
 * DePicture	LIN, LOUT, MIC, HP	LM4871 (HPOUTL,R)
 | 
			
		||||
 * Anubis	LIN, LOUT, MIC, HP	TPA2001D1 (HPOUTL,R)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_widget dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("Line In", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("Line Out", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_route base_map[] = {
 | 
			
		||||
	{ "Headphone Jack", NULL, "LHPOUT"},
 | 
			
		||||
	{ "Headphone Jack", NULL, "RHPOUT"},
 | 
			
		||||
 | 
			
		||||
	{ "Line Out", NULL, "LOUT" },
 | 
			
		||||
	{ "Line Out", NULL, "ROUT" },
 | 
			
		||||
 | 
			
		||||
	{ "LLINEIN", NULL, "Line In"},
 | 
			
		||||
	{ "RLINEIN", NULL, "Line In"},
 | 
			
		||||
 | 
			
		||||
	{ "MICIN", NULL, "Mic Jack"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * simtec_tlv320aic23_init - initialise and add controls
 | 
			
		||||
 * @codec; The codec instance to attach to.
 | 
			
		||||
 *
 | 
			
		||||
 * Attach our controls and configure the necessary codec
 | 
			
		||||
 * mappings for our sound card instance.
 | 
			
		||||
*/
 | 
			
		||||
static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	simtec_audio_init(rtd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(tlv320aic23,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.0-001a",
 | 
			
		||||
				      "tlv320aic3x-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link simtec_dai_aic23 = {
 | 
			
		||||
	.name		= "tlv320aic23",
 | 
			
		||||
	.stream_name	= "TLV320AIC23",
 | 
			
		||||
	.init		= simtec_tlv320aic23_init,
 | 
			
		||||
	SND_SOC_DAILINK_REG(tlv320aic23),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* simtec audio machine driver */
 | 
			
		||||
static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
 | 
			
		||||
	.name		= "Simtec",
 | 
			
		||||
	.owner		= THIS_MODULE,
 | 
			
		||||
	.dai_link	= &simtec_dai_aic23,
 | 
			
		||||
	.num_links	= 1,
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets	= dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
 | 
			
		||||
	.dapm_routes	= base_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(base_map),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int simtec_audio_tlv320aic23_probe(struct platform_device *pd)
 | 
			
		||||
{
 | 
			
		||||
	return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver simtec_audio_tlv320aic23_driver = {
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.name	= "s3c24xx-simtec-tlv320aic23",
 | 
			
		||||
		.pm	= simtec_audio_pm,
 | 
			
		||||
	},
 | 
			
		||||
	.probe	= simtec_audio_tlv320aic23_probe,
 | 
			
		||||
	.remove	= simtec_audio_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(simtec_audio_tlv320aic23_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
 | 
			
		||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,257 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
//
 | 
			
		||||
// Modifications by Christian Pellegrin <chripell@evolware.org>
 | 
			
		||||
//
 | 
			
		||||
// s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2007 Dension Audio Systems Ltd.
 | 
			
		||||
// Author: Zoltan Devai
 | 
			
		||||
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/s3c24xx_uda134x.h>
 | 
			
		||||
 | 
			
		||||
#include "regs-iis.h"
 | 
			
		||||
#include "s3c24xx-i2s.h"
 | 
			
		||||
 | 
			
		||||
struct s3c24xx_uda134x {
 | 
			
		||||
	struct clk *xtal;
 | 
			
		||||
	struct clk *pclk;
 | 
			
		||||
	struct mutex clk_lock;
 | 
			
		||||
	int clk_users;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* #define ENFORCE_RATES 1 */
 | 
			
		||||
/*
 | 
			
		||||
  Unfortunately the S3C24XX in master mode has a limited capacity of
 | 
			
		||||
  generating the clock for the codec. If you define this only rates
 | 
			
		||||
  that are really available will be enforced. But be careful, most
 | 
			
		||||
  user level application just want the usual sampling frequencies (8,
 | 
			
		||||
  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
 | 
			
		||||
  operation for embedded systems. So if you aren't very lucky or your
 | 
			
		||||
  hardware engineer wasn't very forward-looking it's better to leave
 | 
			
		||||
  this undefined. If you do so an approximate value for the requested
 | 
			
		||||
  sampling rate in the range -/+ 5% will be chosen. If this in not
 | 
			
		||||
  possible an error will be returned.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static unsigned int rates[33 * 2];
 | 
			
		||||
#ifdef ENFORCE_RATES
 | 
			
		||||
static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
 | 
			
		||||
	.count	= ARRAY_SIZE(rates),
 | 
			
		||||
	.list	= rates,
 | 
			
		||||
	.mask	= 0,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&priv->clk_lock);
 | 
			
		||||
 | 
			
		||||
	if (priv->clk_users == 0) {
 | 
			
		||||
		priv->xtal = clk_get(rtd->dev, "xtal");
 | 
			
		||||
		if (IS_ERR(priv->xtal)) {
 | 
			
		||||
			dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
 | 
			
		||||
			ret = PTR_ERR(priv->xtal);
 | 
			
		||||
		} else {
 | 
			
		||||
			priv->pclk = clk_get(cpu_dai->dev, "iis");
 | 
			
		||||
			if (IS_ERR(priv->pclk)) {
 | 
			
		||||
				dev_err(rtd->dev, "%s cannot get pclk\n",
 | 
			
		||||
					__func__);
 | 
			
		||||
				clk_put(priv->xtal);
 | 
			
		||||
				ret = PTR_ERR(priv->pclk);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (!ret) {
 | 
			
		||||
			int i, j;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < 2; i++) {
 | 
			
		||||
				int fs = i ? 256 : 384;
 | 
			
		||||
 | 
			
		||||
				rates[i*33] = clk_get_rate(priv->xtal) / fs;
 | 
			
		||||
				for (j = 1; j < 33; j++)
 | 
			
		||||
					rates[i*33 + j] = clk_get_rate(priv->pclk) /
 | 
			
		||||
						(j * fs);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	priv->clk_users += 1;
 | 
			
		||||
	mutex_unlock(&priv->clk_lock);
 | 
			
		||||
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
#ifdef ENFORCE_RATES
 | 
			
		||||
		ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
 | 
			
		||||
						 SNDRV_PCM_HW_PARAM_RATE,
 | 
			
		||||
						 &hw_constraints_rates);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			dev_err(rtd->dev, "%s cannot set constraints\n",
 | 
			
		||||
				__func__);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&priv->clk_lock);
 | 
			
		||||
	priv->clk_users -= 1;
 | 
			
		||||
	if (priv->clk_users == 0) {
 | 
			
		||||
		clk_put(priv->xtal);
 | 
			
		||||
		priv->xtal = NULL;
 | 
			
		||||
		clk_put(priv->pclk);
 | 
			
		||||
		priv->pclk = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&priv->clk_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
					struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	unsigned int clk = 0;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	int clk_source, fs_mode;
 | 
			
		||||
	unsigned long rate = params_rate(params);
 | 
			
		||||
	long err, cerr;
 | 
			
		||||
	unsigned int div;
 | 
			
		||||
	int i, bi;
 | 
			
		||||
 | 
			
		||||
	err = 999999;
 | 
			
		||||
	bi = 0;
 | 
			
		||||
	for (i = 0; i < 2*33; i++) {
 | 
			
		||||
		cerr = rates[i] - rate;
 | 
			
		||||
		if (cerr < 0)
 | 
			
		||||
			cerr = -cerr;
 | 
			
		||||
		if (cerr < err) {
 | 
			
		||||
			err = cerr;
 | 
			
		||||
			bi = i;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (bi / 33 == 1)
 | 
			
		||||
		fs_mode = S3C2410_IISMOD_256FS;
 | 
			
		||||
	else
 | 
			
		||||
		fs_mode = S3C2410_IISMOD_384FS;
 | 
			
		||||
	if (bi % 33 == 0) {
 | 
			
		||||
		clk_source = S3C24XX_CLKSRC_MPLL;
 | 
			
		||||
		div = 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		clk_source = S3C24XX_CLKSRC_PCLK;
 | 
			
		||||
		div = bi % 33;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
 | 
			
		||||
 | 
			
		||||
	clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
 | 
			
		||||
		fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
 | 
			
		||||
		clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
 | 
			
		||||
		div, clk, err);
 | 
			
		||||
 | 
			
		||||
	if ((err * 100 / rate) > 5) {
 | 
			
		||||
		dev_err(rtd->dev, "effective frequency too different "
 | 
			
		||||
				  "from desired (%ld%%)\n", err * 100 / rate);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
 | 
			
		||||
			SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
 | 
			
		||||
			S3C2410_IISMOD_32FS);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 | 
			
		||||
			S3C24XX_PRESCALE(div, div));
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set the codec system clock for DAC and ADC */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
 | 
			
		||||
			SND_SOC_CLOCK_OUT);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_ops s3c24xx_uda134x_ops = {
 | 
			
		||||
	.startup = s3c24xx_uda134x_startup,
 | 
			
		||||
	.shutdown = s3c24xx_uda134x_shutdown,
 | 
			
		||||
	.hw_params = s3c24xx_uda134x_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(uda134x,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("uda134x-codec", "uda134x-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 | 
			
		||||
	.name = "UDA134X",
 | 
			
		||||
	.stream_name = "UDA134X",
 | 
			
		||||
	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
		   SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
	.ops = &s3c24xx_uda134x_ops,
 | 
			
		||||
	SND_SOC_DAILINK_REG(uda134x),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 | 
			
		||||
	.name = "S3C24XX_UDA134X",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = &s3c24xx_uda134x_dai_link,
 | 
			
		||||
	.num_links = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
 | 
			
		||||
	struct s3c24xx_uda134x *priv;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 | 
			
		||||
	if (!priv)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	mutex_init(&priv->clk_lock);
 | 
			
		||||
 | 
			
		||||
	card->dev = &pdev->dev;
 | 
			
		||||
	snd_soc_card_set_drvdata(card, priv);
 | 
			
		||||
 | 
			
		||||
	ret = devm_snd_soc_register_card(&pdev->dev, card);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(&pdev->dev, "failed to register card: %d\n", ret);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver s3c24xx_uda134x_driver = {
 | 
			
		||||
	.probe  = s3c24xx_uda134x_probe,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "s3c24xx_uda134x",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
module_platform_driver(s3c24xx_uda134x_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
 | 
			
		||||
MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,224 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
 | 
			
		||||
//
 | 
			
		||||
// Based on smdk6410_wm8987.c
 | 
			
		||||
//     Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
 | 
			
		||||
//     Graeme Gregory - graeme.gregory@wolfsonmicro.com
 | 
			
		||||
 | 
			
		||||
#include <linux/gpio/consumer.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/jack.h>
 | 
			
		||||
 | 
			
		||||
#include "i2s.h"
 | 
			
		||||
#include "../codecs/wm8750.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * WM8987 is register compatible with WM8750, so using that as base driver.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card snd_soc_smartq;
 | 
			
		||||
 | 
			
		||||
static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
	struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 | 
			
		||||
	unsigned int clk = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	switch (params_rate(params)) {
 | 
			
		||||
	case 8000:
 | 
			
		||||
	case 16000:
 | 
			
		||||
	case 32000:
 | 
			
		||||
	case 48000:
 | 
			
		||||
	case 96000:
 | 
			
		||||
		clk = 12288000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 11025:
 | 
			
		||||
	case 22050:
 | 
			
		||||
	case 44100:
 | 
			
		||||
	case 88200:
 | 
			
		||||
		clk = 11289600;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Use PCLK for I2S signal generation */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
 | 
			
		||||
					0, SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* Gate the RCLK output on PAD */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
 | 
			
		||||
					0, SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* set the codec system clock for DAC and ADC */
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
 | 
			
		||||
				     SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SmartQ WM8987 HiFi DAI operations.
 | 
			
		||||
 */
 | 
			
		||||
static const struct snd_soc_ops smartq_hifi_ops = {
 | 
			
		||||
	.hw_params = smartq_hifi_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack smartq_jack;
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_pin smartq_jack_pins[] = {
 | 
			
		||||
	/* Disable speaker when headphone is plugged in */
 | 
			
		||||
	{
 | 
			
		||||
		.pin	= "Internal Speaker",
 | 
			
		||||
		.mask	= SND_JACK_HEADPHONE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.gpio		= -1,
 | 
			
		||||
		.name		= "headphone detect",
 | 
			
		||||
		.report		= SND_JACK_HEADPHONE,
 | 
			
		||||
		.debounce_time	= 200,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Internal Speaker"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
 | 
			
		||||
	SOC_DAPM_PIN_SWITCH("Internal Mic"),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
 | 
			
		||||
				struct snd_kcontrol *k,
 | 
			
		||||
				int event)
 | 
			
		||||
{
 | 
			
		||||
	struct gpio_desc *gpio = snd_soc_card_get_drvdata(&snd_soc_smartq);
 | 
			
		||||
 | 
			
		||||
	gpiod_set_value(gpio, SND_SOC_DAPM_EVENT_OFF(event));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
 | 
			
		||||
	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 | 
			
		||||
	SND_SOC_DAPM_MIC("Internal Mic", NULL),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct snd_soc_dapm_route audio_map[] = {
 | 
			
		||||
	{"Headphone Jack", NULL, "LOUT2"},
 | 
			
		||||
	{"Headphone Jack", NULL, "ROUT2"},
 | 
			
		||||
 | 
			
		||||
	{"Internal Speaker", NULL, "LOUT2"},
 | 
			
		||||
	{"Internal Speaker", NULL, "ROUT2"},
 | 
			
		||||
 | 
			
		||||
	{"Mic Bias", NULL, "Internal Mic"},
 | 
			
		||||
	{"LINPUT2", NULL, "Mic Bias"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	/* set endpoints to not connected */
 | 
			
		||||
	snd_soc_dapm_nc_pin(dapm, "LINPUT1");
 | 
			
		||||
	snd_soc_dapm_nc_pin(dapm, "RINPUT1");
 | 
			
		||||
	snd_soc_dapm_nc_pin(dapm, "OUT3");
 | 
			
		||||
	snd_soc_dapm_nc_pin(dapm, "ROUT1");
 | 
			
		||||
 | 
			
		||||
	/* Headphone jack detection */
 | 
			
		||||
	err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
 | 
			
		||||
					 SND_JACK_HEADPHONE, &smartq_jack,
 | 
			
		||||
					 smartq_jack_pins,
 | 
			
		||||
					 ARRAY_SIZE(smartq_jack_pins));
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	err = snd_soc_jack_add_gpios(&smartq_jack,
 | 
			
		||||
				     ARRAY_SIZE(smartq_jack_gpios),
 | 
			
		||||
				     smartq_jack_gpios);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(wm8987,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-0x1a", "wm8750-hifi")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link smartq_dai[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.name		= "wm8987",
 | 
			
		||||
		.stream_name	= "SmartQ Hi-Fi",
 | 
			
		||||
		.init		= smartq_wm8987_init,
 | 
			
		||||
		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 | 
			
		||||
				  SND_SOC_DAIFMT_CBS_CFS,
 | 
			
		||||
		.ops		= &smartq_hifi_ops,
 | 
			
		||||
		SND_SOC_DAILINK_REG(wm8987),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card snd_soc_smartq = {
 | 
			
		||||
	.name = "SmartQ",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = smartq_dai,
 | 
			
		||||
	.num_links = ARRAY_SIZE(smartq_dai),
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets = wm8987_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(wm8987_dapm_widgets),
 | 
			
		||||
	.dapm_routes = audio_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(audio_map),
 | 
			
		||||
	.controls = wm8987_smartq_controls,
 | 
			
		||||
	.num_controls = ARRAY_SIZE(wm8987_smartq_controls),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int smartq_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct gpio_desc *gpio;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, &snd_soc_smartq);
 | 
			
		||||
 | 
			
		||||
	/* Initialise GPIOs used by amplifiers */
 | 
			
		||||
	gpio = devm_gpiod_get(&pdev->dev, "amplifiers shutdown",
 | 
			
		||||
			      GPIOD_OUT_HIGH);
 | 
			
		||||
	if (IS_ERR(gpio)) {
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to register GPK12\n");
 | 
			
		||||
		ret = PTR_ERR(gpio);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	snd_soc_card_set_drvdata(&snd_soc_smartq, gpio);
 | 
			
		||||
 | 
			
		||||
	ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_smartq);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to register card\n");
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver smartq_driver = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "smartq-audio",
 | 
			
		||||
	},
 | 
			
		||||
	.probe = smartq_probe,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(smartq_driver);
 | 
			
		||||
 | 
			
		||||
/* Module information */
 | 
			
		||||
MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -1,211 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2009 Samsung Electronics Co. Ltd
 | 
			
		||||
// Author: Jaswinder Singh <jassisinghbrar@gmail.com>
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <sound/soc.h>
 | 
			
		||||
#include <sound/pcm_params.h>
 | 
			
		||||
 | 
			
		||||
#include "../codecs/wm8580.h"
 | 
			
		||||
#include "i2s.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Default CFG switch settings to use this driver:
 | 
			
		||||
 *
 | 
			
		||||
 *   SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* SMDK has a 12MHZ crystal attached to WM8580 */
 | 
			
		||||
#define SMDK_WM8580_FREQ 12000000
 | 
			
		||||
 | 
			
		||||
static int smdk_hw_params(struct snd_pcm_substream *substream,
 | 
			
		||||
	struct snd_pcm_hw_params *params)
 | 
			
		||||
{
 | 
			
		||||
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 | 
			
		||||
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 | 
			
		||||
	unsigned int pll_out;
 | 
			
		||||
	int rfs, ret;
 | 
			
		||||
 | 
			
		||||
	switch (params_width(params)) {
 | 
			
		||||
	case 8:
 | 
			
		||||
	case 16:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
 | 
			
		||||
	 * This criterion can't be met if we request PLL output
 | 
			
		||||
	 * as {8000x256, 64000x256, 11025x256}Hz.
 | 
			
		||||
	 * As a wayout, we rather change rfs to a minimum value that
 | 
			
		||||
	 * results in (params_rate(params) * rfs), and itself, acceptable
 | 
			
		||||
	 * to both - the CODEC and the CPU.
 | 
			
		||||
	 */
 | 
			
		||||
	switch (params_rate(params)) {
 | 
			
		||||
	case 16000:
 | 
			
		||||
	case 22050:
 | 
			
		||||
	case 32000:
 | 
			
		||||
	case 44100:
 | 
			
		||||
	case 48000:
 | 
			
		||||
	case 88200:
 | 
			
		||||
	case 96000:
 | 
			
		||||
		rfs = 256;
 | 
			
		||||
		break;
 | 
			
		||||
	case 64000:
 | 
			
		||||
		rfs = 384;
 | 
			
		||||
		break;
 | 
			
		||||
	case 8000:
 | 
			
		||||
	case 11025:
 | 
			
		||||
		rfs = 512;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	pll_out = params_rate(params) * rfs;
 | 
			
		||||
 | 
			
		||||
	/* Set WM8580 to drive MCLK from its PLLA */
 | 
			
		||||
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
 | 
			
		||||
					WM8580_CLKSRC_PLLA);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
 | 
			
		||||
					SMDK_WM8580_FREQ, pll_out);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
 | 
			
		||||
				     pll_out, SND_SOC_CLOCK_IN);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SMDK WM8580 DAI operations.
 | 
			
		||||
 */
 | 
			
		||||
static const struct snd_soc_ops smdk_ops = {
 | 
			
		||||
	.hw_params = smdk_hw_params,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* SMDK Playback widgets */
 | 
			
		||||
static const struct snd_soc_dapm_widget smdk_wm8580_dapm_widgets[] = {
 | 
			
		||||
	SND_SOC_DAPM_HP("Front", NULL),
 | 
			
		||||
	SND_SOC_DAPM_HP("Center+Sub", NULL),
 | 
			
		||||
	SND_SOC_DAPM_HP("Rear", NULL),
 | 
			
		||||
 | 
			
		||||
	SND_SOC_DAPM_MIC("MicIn", NULL),
 | 
			
		||||
	SND_SOC_DAPM_LINE("LineIn", NULL),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* SMDK-PAIFTX connections */
 | 
			
		||||
static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
 | 
			
		||||
	/* MicIn feeds AINL */
 | 
			
		||||
	{"AINL", NULL, "MicIn"},
 | 
			
		||||
 | 
			
		||||
	/* LineIn feeds AINL/R */
 | 
			
		||||
	{"AINL", NULL, "LineIn"},
 | 
			
		||||
	{"AINR", NULL, "LineIn"},
 | 
			
		||||
 | 
			
		||||
	/* Front Left/Right are fed VOUT1L/R */
 | 
			
		||||
	{"Front", NULL, "VOUT1L"},
 | 
			
		||||
	{"Front", NULL, "VOUT1R"},
 | 
			
		||||
 | 
			
		||||
	/* Center/Sub are fed VOUT2L/R */
 | 
			
		||||
	{"Center+Sub", NULL, "VOUT2L"},
 | 
			
		||||
	{"Center+Sub", NULL, "VOUT2R"},
 | 
			
		||||
 | 
			
		||||
	/* Rear Left/Right are fed VOUT3L/R */
 | 
			
		||||
	{"Rear", NULL, "VOUT3L"},
 | 
			
		||||
	{"Rear", NULL, "VOUT3R"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
 | 
			
		||||
{
 | 
			
		||||
	/* Enabling the microphone requires the fitting of a 0R
 | 
			
		||||
	 * resistor to connect the line from the microphone jack.
 | 
			
		||||
	 */
 | 
			
		||||
	snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	PRI_PLAYBACK = 0,
 | 
			
		||||
	PRI_CAPTURE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
 | 
			
		||||
	SND_SOC_DAIFMT_CBM_CFM)
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(paif_rx,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.2")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8580.0-001b", "wm8580-hifi-playback")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
 | 
			
		||||
 | 
			
		||||
SND_SOC_DAILINK_DEFS(paif_tx,
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.2")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_CODEC("wm8580.0-001b", "wm8580-hifi-capture")),
 | 
			
		||||
	DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_dai_link smdk_dai[] = {
 | 
			
		||||
	[PRI_PLAYBACK] = { /* Primary Playback i/f */
 | 
			
		||||
		.name = "WM8580 PAIF RX",
 | 
			
		||||
		.stream_name = "Playback",
 | 
			
		||||
		.dai_fmt = SMDK_DAI_FMT,
 | 
			
		||||
		.ops = &smdk_ops,
 | 
			
		||||
		SND_SOC_DAILINK_REG(paif_rx),
 | 
			
		||||
	},
 | 
			
		||||
	[PRI_CAPTURE] = { /* Primary Capture i/f */
 | 
			
		||||
		.name = "WM8580 PAIF TX",
 | 
			
		||||
		.stream_name = "Capture",
 | 
			
		||||
		.dai_fmt = SMDK_DAI_FMT,
 | 
			
		||||
		.init = smdk_wm8580_init_paiftx,
 | 
			
		||||
		.ops = &smdk_ops,
 | 
			
		||||
		SND_SOC_DAILINK_REG(paif_tx),
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct snd_soc_card smdk = {
 | 
			
		||||
	.name = "SMDK-I2S",
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.dai_link = smdk_dai,
 | 
			
		||||
	.num_links = ARRAY_SIZE(smdk_dai),
 | 
			
		||||
 | 
			
		||||
	.dapm_widgets = smdk_wm8580_dapm_widgets,
 | 
			
		||||
	.num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets),
 | 
			
		||||
	.dapm_routes = smdk_wm8580_audio_map,
 | 
			
		||||
	.num_dapm_routes = ARRAY_SIZE(smdk_wm8580_audio_map),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct platform_device *smdk_snd_device;
 | 
			
		||||
 | 
			
		||||
static int __init smdk_audio_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	smdk_snd_device = platform_device_alloc("soc-audio", -1);
 | 
			
		||||
	if (!smdk_snd_device)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(smdk_snd_device, &smdk);
 | 
			
		||||
	ret = platform_device_add(smdk_snd_device);
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		platform_device_put(smdk_snd_device);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
module_init(smdk_audio_init);
 | 
			
		||||
 | 
			
		||||
static void __exit smdk_audio_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_device_unregister(smdk_snd_device);
 | 
			
		||||
}
 | 
			
		||||
module_exit(smdk_audio_exit);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Jaswinder Singh, jassisinghbrar@gmail.com");
 | 
			
		||||
MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
		Loading…
	
		Reference in a new issue