18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * uda134x.c  --  UDA134X ALSA SoC Codec driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Modifications by Christian Pellegrin <chripell@evolware.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright 2007 Dension Audio Systems Ltd.
88c2ecf20Sopenharmony_ci * Author: Zoltan Devai
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <sound/pcm.h>
178c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
188c2ecf20Sopenharmony_ci#include <sound/soc.h>
198c2ecf20Sopenharmony_ci#include <sound/initval.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <sound/uda134x.h>
228c2ecf20Sopenharmony_ci#include <sound/l3.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "uda134x.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
288c2ecf20Sopenharmony_ci#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
298c2ecf20Sopenharmony_ci		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct uda134x_priv {
328c2ecf20Sopenharmony_ci	int sysclk;
338c2ecf20Sopenharmony_ci	int dai_fmt;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	struct snd_pcm_substream *master_substream;
368c2ecf20Sopenharmony_ci	struct snd_pcm_substream *slave_substream;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	struct regmap *regmap;
398c2ecf20Sopenharmony_ci	struct uda134x_platform_data *pd;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct reg_default uda134x_reg_defaults[] = {
438c2ecf20Sopenharmony_ci	{ UDA134X_EA000, 0x04 },
448c2ecf20Sopenharmony_ci	{ UDA134X_EA001, 0x04 },
458c2ecf20Sopenharmony_ci	{ UDA134X_EA010, 0x04 },
468c2ecf20Sopenharmony_ci	{ UDA134X_EA011, 0x00 },
478c2ecf20Sopenharmony_ci	{ UDA134X_EA100, 0x00 },
488c2ecf20Sopenharmony_ci	{ UDA134X_EA101, 0x00 },
498c2ecf20Sopenharmony_ci	{ UDA134X_EA110, 0x00 },
508c2ecf20Sopenharmony_ci	{ UDA134X_EA111, 0x00 },
518c2ecf20Sopenharmony_ci	{ UDA134X_STATUS0, 0x00 },
528c2ecf20Sopenharmony_ci	{ UDA134X_STATUS1, 0x03 },
538c2ecf20Sopenharmony_ci	{ UDA134X_DATA000, 0x00 },
548c2ecf20Sopenharmony_ci	{ UDA134X_DATA001, 0x00 },
558c2ecf20Sopenharmony_ci	{ UDA134X_DATA010, 0x00 },
568c2ecf20Sopenharmony_ci	{ UDA134X_DATA011, 0x00 },
578c2ecf20Sopenharmony_ci	{ UDA134X_DATA1, 0x00 },
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * Write to the uda134x registers
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistatic int uda134x_regmap_write(void *context, unsigned int reg,
658c2ecf20Sopenharmony_ci	unsigned int value)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct uda134x_platform_data *pd = context;
688c2ecf20Sopenharmony_ci	int ret;
698c2ecf20Sopenharmony_ci	u8 addr;
708c2ecf20Sopenharmony_ci	u8 data = value;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	switch (reg) {
738c2ecf20Sopenharmony_ci	case UDA134X_STATUS0:
748c2ecf20Sopenharmony_ci	case UDA134X_STATUS1:
758c2ecf20Sopenharmony_ci		addr = UDA134X_STATUS_ADDR;
768c2ecf20Sopenharmony_ci		data |= (reg - UDA134X_STATUS0) << 7;
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	case UDA134X_DATA000:
798c2ecf20Sopenharmony_ci	case UDA134X_DATA001:
808c2ecf20Sopenharmony_ci	case UDA134X_DATA010:
818c2ecf20Sopenharmony_ci	case UDA134X_DATA011:
828c2ecf20Sopenharmony_ci		addr = UDA134X_DATA0_ADDR;
838c2ecf20Sopenharmony_ci		data |= (reg - UDA134X_DATA000) << 6;
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	case UDA134X_DATA1:
868c2ecf20Sopenharmony_ci		addr = UDA134X_DATA1_ADDR;
878c2ecf20Sopenharmony_ci		break;
888c2ecf20Sopenharmony_ci	default:
898c2ecf20Sopenharmony_ci		/* It's an extended address register */
908c2ecf20Sopenharmony_ci		addr =  (reg | UDA134X_EXTADDR_PREFIX);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		ret = l3_write(&pd->l3,
938c2ecf20Sopenharmony_ci			       UDA134X_DATA0_ADDR, &addr, 1);
948c2ecf20Sopenharmony_ci		if (ret != 1)
958c2ecf20Sopenharmony_ci			return -EIO;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		addr = UDA134X_DATA0_ADDR;
988c2ecf20Sopenharmony_ci		data = (value | UDA134X_EXTDATA_PREFIX);
998c2ecf20Sopenharmony_ci		break;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	ret = l3_write(&pd->l3,
1038c2ecf20Sopenharmony_ci		       addr, &data, 1);
1048c2ecf20Sopenharmony_ci	if (ret != 1)
1058c2ecf20Sopenharmony_ci		return -EIO;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic inline void uda134x_reset(struct snd_soc_component *component)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
1138c2ecf20Sopenharmony_ci	unsigned int mask = 1<<6;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
1168c2ecf20Sopenharmony_ci	msleep(1);
1178c2ecf20Sopenharmony_ci	regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int uda134x_mute(struct snd_soc_dai *dai, int mute, int direction)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
1238c2ecf20Sopenharmony_ci	unsigned int mask = 1<<2;
1248c2ecf20Sopenharmony_ci	unsigned int val;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	pr_debug("%s mute: %d\n", __func__, mute);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (mute)
1298c2ecf20Sopenharmony_ci		val = mask;
1308c2ecf20Sopenharmony_ci	else
1318c2ecf20Sopenharmony_ci		val = 0;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int uda134x_startup(struct snd_pcm_substream *substream,
1378c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1408c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
1418c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *master_runtime;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (uda134x->master_substream) {
1448c2ecf20Sopenharmony_ci		master_runtime = uda134x->master_substream->runtime;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		pr_debug("%s constraining to %d bits at %d\n", __func__,
1478c2ecf20Sopenharmony_ci			 master_runtime->sample_bits,
1488c2ecf20Sopenharmony_ci			 master_runtime->rate);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		snd_pcm_hw_constraint_single(substream->runtime,
1518c2ecf20Sopenharmony_ci					     SNDRV_PCM_HW_PARAM_RATE,
1528c2ecf20Sopenharmony_ci					     master_runtime->rate);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		snd_pcm_hw_constraint_single(substream->runtime,
1558c2ecf20Sopenharmony_ci					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
1568c2ecf20Sopenharmony_ci					     master_runtime->sample_bits);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		uda134x->slave_substream = substream;
1598c2ecf20Sopenharmony_ci	} else
1608c2ecf20Sopenharmony_ci		uda134x->master_substream = substream;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return 0;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void uda134x_shutdown(struct snd_pcm_substream *substream,
1668c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1698c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (uda134x->master_substream == substream)
1728c2ecf20Sopenharmony_ci		uda134x->master_substream = uda134x->slave_substream;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	uda134x->slave_substream = NULL;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic int uda134x_hw_params(struct snd_pcm_substream *substream,
1788c2ecf20Sopenharmony_ci	struct snd_pcm_hw_params *params,
1798c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1828c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
1838c2ecf20Sopenharmony_ci	unsigned int hw_params = 0;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (substream == uda134x->slave_substream) {
1868c2ecf20Sopenharmony_ci		pr_debug("%s ignoring hw_params for slave substream\n",
1878c2ecf20Sopenharmony_ci			 __func__);
1888c2ecf20Sopenharmony_ci		return 0;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	pr_debug("%s sysclk: %d, rate:%d\n", __func__,
1928c2ecf20Sopenharmony_ci		 uda134x->sysclk, params_rate(params));
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* set SYSCLK / fs ratio */
1958c2ecf20Sopenharmony_ci	switch (uda134x->sysclk / params_rate(params)) {
1968c2ecf20Sopenharmony_ci	case 512:
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci	case 384:
1998c2ecf20Sopenharmony_ci		hw_params |= (1<<4);
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	case 256:
2028c2ecf20Sopenharmony_ci		hw_params |= (1<<5);
2038c2ecf20Sopenharmony_ci		break;
2048c2ecf20Sopenharmony_ci	default:
2058c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s unsupported fs\n", __func__);
2068c2ecf20Sopenharmony_ci		return -EINVAL;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
2108c2ecf20Sopenharmony_ci		 uda134x->dai_fmt, params_format(params));
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* set DAI format and word length */
2138c2ecf20Sopenharmony_ci	switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2148c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
2178c2ecf20Sopenharmony_ci		switch (params_width(params)) {
2188c2ecf20Sopenharmony_ci		case 16:
2198c2ecf20Sopenharmony_ci			hw_params |= (1<<1);
2208c2ecf20Sopenharmony_ci			break;
2218c2ecf20Sopenharmony_ci		case 18:
2228c2ecf20Sopenharmony_ci			hw_params |= (1<<2);
2238c2ecf20Sopenharmony_ci			break;
2248c2ecf20Sopenharmony_ci		case 20:
2258c2ecf20Sopenharmony_ci			hw_params |= ((1<<2) | (1<<1));
2268c2ecf20Sopenharmony_ci			break;
2278c2ecf20Sopenharmony_ci		default:
2288c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s unsupported format (right)\n",
2298c2ecf20Sopenharmony_ci			       __func__);
2308c2ecf20Sopenharmony_ci			return -EINVAL;
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
2348c2ecf20Sopenharmony_ci		hw_params |= (1<<3);
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	default:
2378c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s unsupported format\n", __func__);
2388c2ecf20Sopenharmony_ci		return -EINVAL;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
2428c2ecf20Sopenharmony_ci		STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
2468c2ecf20Sopenharmony_ci				  int clk_id, unsigned int freq, int dir)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
2498c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
2528c2ecf20Sopenharmony_ci		 clk_id, freq, dir);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
2558c2ecf20Sopenharmony_ci	   because the codec is slave. Of course limitations of the clock
2568c2ecf20Sopenharmony_ci	   master (the IIS controller) apply.
2578c2ecf20Sopenharmony_ci	   We'll error out on set_hw_params if it's not OK */
2588c2ecf20Sopenharmony_ci	if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
2598c2ecf20Sopenharmony_ci		uda134x->sysclk = freq;
2608c2ecf20Sopenharmony_ci		return 0;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s unsupported sysclk\n", __func__);
2648c2ecf20Sopenharmony_ci	return -EINVAL;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
2688c2ecf20Sopenharmony_ci			       unsigned int fmt)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
2718c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	pr_debug("%s fmt: %08X\n", __func__, fmt);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* codec supports only full slave mode */
2768c2ecf20Sopenharmony_ci	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
2778c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s unsupported slave mode\n", __func__);
2788c2ecf20Sopenharmony_ci		return -EINVAL;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* no support for clock inversion */
2828c2ecf20Sopenharmony_ci	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
2838c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
2848c2ecf20Sopenharmony_ci		return -EINVAL;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* We can't setup DAI format here as it depends on the word bit num */
2888c2ecf20Sopenharmony_ci	/* so let's just store the value for later */
2898c2ecf20Sopenharmony_ci	uda134x->dai_fmt = fmt;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int uda134x_set_bias_level(struct snd_soc_component *component,
2958c2ecf20Sopenharmony_ci				  enum snd_soc_bias_level level)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
2988c2ecf20Sopenharmony_ci	struct uda134x_platform_data *pd = uda134x->pd;
2998c2ecf20Sopenharmony_ci	pr_debug("%s bias level %d\n", __func__, level);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	switch (level) {
3028c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_ON:
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
3058c2ecf20Sopenharmony_ci		/* power on */
3068c2ecf20Sopenharmony_ci		if (pd->power) {
3078c2ecf20Sopenharmony_ci			pd->power(1);
3088c2ecf20Sopenharmony_ci			regcache_sync(uda134x->regmap);
3098c2ecf20Sopenharmony_ci		}
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_OFF:
3148c2ecf20Sopenharmony_ci		/* power off */
3158c2ecf20Sopenharmony_ci		if (pd->power) {
3168c2ecf20Sopenharmony_ci			pd->power(0);
3178c2ecf20Sopenharmony_ci			regcache_mark_dirty(uda134x->regmap);
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci		break;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
3258c2ecf20Sopenharmony_ci					    "Minimum2", "Maximum"};
3268c2ecf20Sopenharmony_cistatic const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
3278c2ecf20Sopenharmony_cistatic const char *uda134x_mixmode[] = {"Differential", "Analog1",
3288c2ecf20Sopenharmony_ci					"Analog2", "Both"};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic const struct soc_enum uda134x_mixer_enum[] = {
3318c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
3328c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
3338c2ecf20Sopenharmony_ciSOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
3348c2ecf20Sopenharmony_ci};
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uda1341_snd_controls[] = {
3378c2ecf20Sopenharmony_ciSOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
3388c2ecf20Sopenharmony_ciSOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
3398c2ecf20Sopenharmony_ciSOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
3408c2ecf20Sopenharmony_ciSOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ciSOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
3438c2ecf20Sopenharmony_ciSOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ciSOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
3468c2ecf20Sopenharmony_ciSOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ciSOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
3498c2ecf20Sopenharmony_ciSOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
3508c2ecf20Sopenharmony_ciSOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ciSOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
3538c2ecf20Sopenharmony_ciSOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
3548c2ecf20Sopenharmony_ciSOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciSOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
3578c2ecf20Sopenharmony_ciSOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
3588c2ecf20Sopenharmony_ciSOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
3598c2ecf20Sopenharmony_ciSOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
3608c2ecf20Sopenharmony_ciSOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
3618c2ecf20Sopenharmony_ciSOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
3628c2ecf20Sopenharmony_ci};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uda1340_snd_controls[] = {
3658c2ecf20Sopenharmony_ciSOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ciSOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
3688c2ecf20Sopenharmony_ciSOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciSOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
3718c2ecf20Sopenharmony_ciSOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciSOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uda1345_snd_controls[] = {
3778c2ecf20Sopenharmony_ciSOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ciSOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ciSOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* UDA1341 has the DAC/ADC power down in STATUS1 */
3858c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
3868c2ecf20Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
3878c2ecf20Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
3888c2ecf20Sopenharmony_ci};
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
3918c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
3928c2ecf20Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
3938c2ecf20Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
3948c2ecf20Sopenharmony_ci};
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/* Common DAPM widgets */
3978c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
3988c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("VINL1"),
3998c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("VINR1"),
4008c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("VINL2"),
4018c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("VINR2"),
4028c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("VOUTL"),
4038c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("VOUTR"),
4048c2ecf20Sopenharmony_ci};
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
4078c2ecf20Sopenharmony_ci	{ "ADC", NULL, "VINL1" },
4088c2ecf20Sopenharmony_ci	{ "ADC", NULL, "VINR1" },
4098c2ecf20Sopenharmony_ci	{ "ADC", NULL, "VINL2" },
4108c2ecf20Sopenharmony_ci	{ "ADC", NULL, "VINR2" },
4118c2ecf20Sopenharmony_ci	{ "VOUTL", NULL, "DAC" },
4128c2ecf20Sopenharmony_ci	{ "VOUTR", NULL, "DAC" },
4138c2ecf20Sopenharmony_ci};
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops uda134x_dai_ops = {
4168c2ecf20Sopenharmony_ci	.startup	= uda134x_startup,
4178c2ecf20Sopenharmony_ci	.shutdown	= uda134x_shutdown,
4188c2ecf20Sopenharmony_ci	.hw_params	= uda134x_hw_params,
4198c2ecf20Sopenharmony_ci	.mute_stream	= uda134x_mute,
4208c2ecf20Sopenharmony_ci	.set_sysclk	= uda134x_set_dai_sysclk,
4218c2ecf20Sopenharmony_ci	.set_fmt	= uda134x_set_dai_fmt,
4228c2ecf20Sopenharmony_ci	.no_capture_mute = 1,
4238c2ecf20Sopenharmony_ci};
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver uda134x_dai = {
4268c2ecf20Sopenharmony_ci	.name = "uda134x-hifi",
4278c2ecf20Sopenharmony_ci	/* playback capabilities */
4288c2ecf20Sopenharmony_ci	.playback = {
4298c2ecf20Sopenharmony_ci		.stream_name = "Playback",
4308c2ecf20Sopenharmony_ci		.channels_min = 1,
4318c2ecf20Sopenharmony_ci		.channels_max = 2,
4328c2ecf20Sopenharmony_ci		.rates = UDA134X_RATES,
4338c2ecf20Sopenharmony_ci		.formats = UDA134X_FORMATS,
4348c2ecf20Sopenharmony_ci	},
4358c2ecf20Sopenharmony_ci	/* capture capabilities */
4368c2ecf20Sopenharmony_ci	.capture = {
4378c2ecf20Sopenharmony_ci		.stream_name = "Capture",
4388c2ecf20Sopenharmony_ci		.channels_min = 1,
4398c2ecf20Sopenharmony_ci		.channels_max = 2,
4408c2ecf20Sopenharmony_ci		.rates = UDA134X_RATES,
4418c2ecf20Sopenharmony_ci		.formats = UDA134X_FORMATS,
4428c2ecf20Sopenharmony_ci	},
4438c2ecf20Sopenharmony_ci	/* pcm operations */
4448c2ecf20Sopenharmony_ci	.ops = &uda134x_dai_ops,
4458c2ecf20Sopenharmony_ci};
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int uda134x_soc_probe(struct snd_soc_component *component)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
4508c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
4518c2ecf20Sopenharmony_ci	struct uda134x_platform_data *pd = uda134x->pd;
4528c2ecf20Sopenharmony_ci	const struct snd_soc_dapm_widget *widgets;
4538c2ecf20Sopenharmony_ci	unsigned num_widgets;
4548c2ecf20Sopenharmony_ci	int ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	printk(KERN_INFO "UDA134X SoC Audio Codec\n");
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	switch (pd->model) {
4598c2ecf20Sopenharmony_ci	case UDA134X_UDA1340:
4608c2ecf20Sopenharmony_ci	case UDA134X_UDA1341:
4618c2ecf20Sopenharmony_ci	case UDA134X_UDA1344:
4628c2ecf20Sopenharmony_ci	case UDA134X_UDA1345:
4638c2ecf20Sopenharmony_ci		break;
4648c2ecf20Sopenharmony_ci	default:
4658c2ecf20Sopenharmony_ci		printk(KERN_ERR "UDA134X SoC codec: "
4668c2ecf20Sopenharmony_ci		       "unsupported model %d\n",
4678c2ecf20Sopenharmony_ci			pd->model);
4688c2ecf20Sopenharmony_ci		return -EINVAL;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (pd->power)
4728c2ecf20Sopenharmony_ci		pd->power(1);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	uda134x_reset(component);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (pd->model == UDA134X_UDA1341) {
4778c2ecf20Sopenharmony_ci		widgets = uda1341_dapm_widgets;
4788c2ecf20Sopenharmony_ci		num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
4798c2ecf20Sopenharmony_ci	} else {
4808c2ecf20Sopenharmony_ci		widgets = uda1340_dapm_widgets;
4818c2ecf20Sopenharmony_ci		num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
4858c2ecf20Sopenharmony_ci	if (ret) {
4868c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s failed to register dapm controls: %d",
4878c2ecf20Sopenharmony_ci			__func__, ret);
4888c2ecf20Sopenharmony_ci		return ret;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	switch (pd->model) {
4928c2ecf20Sopenharmony_ci	case UDA134X_UDA1340:
4938c2ecf20Sopenharmony_ci	case UDA134X_UDA1344:
4948c2ecf20Sopenharmony_ci		ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
4958c2ecf20Sopenharmony_ci					ARRAY_SIZE(uda1340_snd_controls));
4968c2ecf20Sopenharmony_ci	break;
4978c2ecf20Sopenharmony_ci	case UDA134X_UDA1341:
4988c2ecf20Sopenharmony_ci		ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
4998c2ecf20Sopenharmony_ci					ARRAY_SIZE(uda1341_snd_controls));
5008c2ecf20Sopenharmony_ci	break;
5018c2ecf20Sopenharmony_ci	case UDA134X_UDA1345:
5028c2ecf20Sopenharmony_ci		ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
5038c2ecf20Sopenharmony_ci					ARRAY_SIZE(uda1345_snd_controls));
5048c2ecf20Sopenharmony_ci	break;
5058c2ecf20Sopenharmony_ci	default:
5068c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s unknown codec type: %d",
5078c2ecf20Sopenharmony_ci			__func__, pd->model);
5088c2ecf20Sopenharmony_ci		return -EINVAL;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (ret < 0) {
5128c2ecf20Sopenharmony_ci		printk(KERN_ERR "UDA134X: failed to register controls\n");
5138c2ecf20Sopenharmony_ci		return ret;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return 0;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_uda134x = {
5208c2ecf20Sopenharmony_ci	.probe			= uda134x_soc_probe,
5218c2ecf20Sopenharmony_ci	.set_bias_level		= uda134x_set_bias_level,
5228c2ecf20Sopenharmony_ci	.dapm_widgets		= uda134x_dapm_widgets,
5238c2ecf20Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),
5248c2ecf20Sopenharmony_ci	.dapm_routes		= uda134x_dapm_routes,
5258c2ecf20Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),
5268c2ecf20Sopenharmony_ci	.suspend_bias_off	= 1,
5278c2ecf20Sopenharmony_ci	.idle_bias_on		= 1,
5288c2ecf20Sopenharmony_ci	.use_pmdown_time	= 1,
5298c2ecf20Sopenharmony_ci	.endianness		= 1,
5308c2ecf20Sopenharmony_ci	.non_legacy_dai_naming	= 1,
5318c2ecf20Sopenharmony_ci};
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic const struct regmap_config uda134x_regmap_config = {
5348c2ecf20Sopenharmony_ci	.reg_bits = 8,
5358c2ecf20Sopenharmony_ci	.val_bits = 8,
5368c2ecf20Sopenharmony_ci	.max_register = UDA134X_DATA1,
5378c2ecf20Sopenharmony_ci	.reg_defaults = uda134x_reg_defaults,
5388c2ecf20Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
5398c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	.reg_write = uda134x_regmap_write,
5428c2ecf20Sopenharmony_ci};
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int uda134x_codec_probe(struct platform_device *pdev)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct uda134x_platform_data *pd = pdev->dev.platform_data;
5478c2ecf20Sopenharmony_ci	struct uda134x_priv *uda134x;
5488c2ecf20Sopenharmony_ci	int ret;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (!pd) {
5518c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Missing L3 bitbang function\n");
5528c2ecf20Sopenharmony_ci		return -ENODEV;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
5568c2ecf20Sopenharmony_ci	if (!uda134x)
5578c2ecf20Sopenharmony_ci		return -ENOMEM;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	uda134x->pd = pd;
5608c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, uda134x);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (pd->l3.use_gpios) {
5638c2ecf20Sopenharmony_ci		ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3);
5648c2ecf20Sopenharmony_ci		if (ret < 0)
5658c2ecf20Sopenharmony_ci			return ret;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
5698c2ecf20Sopenharmony_ci		&uda134x_regmap_config);
5708c2ecf20Sopenharmony_ci	if (IS_ERR(uda134x->regmap))
5718c2ecf20Sopenharmony_ci		return PTR_ERR(uda134x->regmap);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return devm_snd_soc_register_component(&pdev->dev,
5748c2ecf20Sopenharmony_ci			&soc_component_dev_uda134x, &uda134x_dai, 1);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic struct platform_driver uda134x_codec_driver = {
5788c2ecf20Sopenharmony_ci	.driver = {
5798c2ecf20Sopenharmony_ci		.name = "uda134x-codec",
5808c2ecf20Sopenharmony_ci	},
5818c2ecf20Sopenharmony_ci	.probe = uda134x_codec_probe,
5828c2ecf20Sopenharmony_ci};
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cimodule_platform_driver(uda134x_codec_driver);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
5878c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
5888c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
589