18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2015
48c2ecf20Sopenharmony_ci * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
58c2ecf20Sopenharmony_ci *          for STMicroelectronics.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/regmap.h>
118c2ecf20Sopenharmony_ci#include <linux/reset.h>
128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <sound/soc.h>
158c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* DAC definitions */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* stih407 DAC registers */
208c2ecf20Sopenharmony_ci/* sysconf 5041: Audio-Gue-Control */
218c2ecf20Sopenharmony_ci#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
228c2ecf20Sopenharmony_ci/* sysconf 5042: Audio-DAC-Control */
238c2ecf20Sopenharmony_ci#define STIH407_AUDIO_DAC_CTRL 0x000000A8
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* DAC definitions */
268c2ecf20Sopenharmony_ci#define STIH407_DAC_SOFTMUTE		0x0
278c2ecf20Sopenharmony_ci#define STIH407_DAC_STANDBY_ANA		0x1
288c2ecf20Sopenharmony_ci#define STIH407_DAC_STANDBY		0x2
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define STIH407_DAC_SOFTMUTE_MASK	BIT(STIH407_DAC_SOFTMUTE)
318c2ecf20Sopenharmony_ci#define STIH407_DAC_STANDBY_ANA_MASK    BIT(STIH407_DAC_STANDBY_ANA)
328c2ecf20Sopenharmony_ci#define STIH407_DAC_STANDBY_MASK        BIT(STIH407_DAC_STANDBY)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* SPDIF definitions */
358c2ecf20Sopenharmony_ci#define SPDIF_BIPHASE_ENABLE		0x6
368c2ecf20Sopenharmony_ci#define SPDIF_BIPHASE_IDLE		0x7
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define SPDIF_BIPHASE_ENABLE_MASK	BIT(SPDIF_BIPHASE_ENABLE)
398c2ecf20Sopenharmony_ci#define SPDIF_BIPHASE_IDLE_MASK		BIT(SPDIF_BIPHASE_IDLE)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cienum {
428c2ecf20Sopenharmony_ci	STI_SAS_DAI_SPDIF_OUT,
438c2ecf20Sopenharmony_ci	STI_SAS_DAI_ANALOG_OUT,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic const struct reg_default stih407_sas_reg_defaults[] = {
478c2ecf20Sopenharmony_ci	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
488c2ecf20Sopenharmony_ci	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct sti_dac_audio {
528c2ecf20Sopenharmony_ci	struct regmap *regmap;
538c2ecf20Sopenharmony_ci	struct regmap *virt_regmap;
548c2ecf20Sopenharmony_ci	struct regmap_field  **field;
558c2ecf20Sopenharmony_ci	struct reset_control *rst;
568c2ecf20Sopenharmony_ci	int mclk;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct sti_spdif_audio {
608c2ecf20Sopenharmony_ci	struct regmap *regmap;
618c2ecf20Sopenharmony_ci	struct regmap_field  **field;
628c2ecf20Sopenharmony_ci	int mclk;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* device data structure */
668c2ecf20Sopenharmony_cistruct sti_sas_dev_data {
678c2ecf20Sopenharmony_ci	const struct regmap_config *regmap;
688c2ecf20Sopenharmony_ci	const struct snd_soc_dai_ops *dac_ops;  /* DAC function callbacks */
698c2ecf20Sopenharmony_ci	const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
708c2ecf20Sopenharmony_ci	const int num_dapm_widgets; /* dapms declaration */
718c2ecf20Sopenharmony_ci	const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
728c2ecf20Sopenharmony_ci	const int num_dapm_routes; /* route declaration */
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* driver data structure */
768c2ecf20Sopenharmony_cistruct sti_sas_data {
778c2ecf20Sopenharmony_ci	struct device *dev;
788c2ecf20Sopenharmony_ci	const struct sti_sas_dev_data *dev_data;
798c2ecf20Sopenharmony_ci	struct sti_dac_audio dac;
808c2ecf20Sopenharmony_ci	struct sti_spdif_audio spdif;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Read a register from the sysconf reg bank */
848c2ecf20Sopenharmony_cistatic int sti_sas_read_reg(void *context, unsigned int reg,
858c2ecf20Sopenharmony_ci			    unsigned int *value)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = context;
888c2ecf20Sopenharmony_ci	int status;
898c2ecf20Sopenharmony_ci	u32 val;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	status = regmap_read(drvdata->dac.regmap, reg, &val);
928c2ecf20Sopenharmony_ci	*value = (unsigned int)val;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return status;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Read a register from the sysconf reg bank */
988c2ecf20Sopenharmony_cistatic int sti_sas_write_reg(void *context, unsigned int reg,
998c2ecf20Sopenharmony_ci			     unsigned int value)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = context;
1028c2ecf20Sopenharmony_ci	int status;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	status = regmap_write(drvdata->dac.regmap, reg, value);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return status;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int  sti_sas_init_sas_registers(struct snd_soc_component *component,
1108c2ecf20Sopenharmony_ci				       struct sti_sas_data *data)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	int ret;
1138c2ecf20Sopenharmony_ci	/*
1148c2ecf20Sopenharmony_ci	 * DAC and SPDIF are activated by default
1158c2ecf20Sopenharmony_ci	 * put them in IDLE to save power
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Initialise bi-phase formatter to disabled */
1198c2ecf20Sopenharmony_ci	ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
1208c2ecf20Sopenharmony_ci				  SPDIF_BIPHASE_ENABLE_MASK, 0);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (!ret)
1238c2ecf20Sopenharmony_ci		/* Initialise bi-phase formatter idle value to 0 */
1248c2ecf20Sopenharmony_ci		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
1258c2ecf20Sopenharmony_ci					  SPDIF_BIPHASE_IDLE_MASK, 0);
1268c2ecf20Sopenharmony_ci	if (ret < 0) {
1278c2ecf20Sopenharmony_ci		dev_err(component->dev, "Failed to update SPDIF registers\n");
1288c2ecf20Sopenharmony_ci		return ret;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Init DAC configuration */
1328c2ecf20Sopenharmony_ci	/* init configuration */
1338c2ecf20Sopenharmony_ci	ret =  snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
1348c2ecf20Sopenharmony_ci				   STIH407_DAC_STANDBY_MASK,
1358c2ecf20Sopenharmony_ci				   STIH407_DAC_STANDBY_MASK);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (!ret)
1388c2ecf20Sopenharmony_ci		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
1398c2ecf20Sopenharmony_ci					  STIH407_DAC_STANDBY_ANA_MASK,
1408c2ecf20Sopenharmony_ci					  STIH407_DAC_STANDBY_ANA_MASK);
1418c2ecf20Sopenharmony_ci	if (!ret)
1428c2ecf20Sopenharmony_ci		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
1438c2ecf20Sopenharmony_ci					  STIH407_DAC_SOFTMUTE_MASK,
1448c2ecf20Sopenharmony_ci					  STIH407_DAC_SOFTMUTE_MASK);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	if (ret < 0) {
1478c2ecf20Sopenharmony_ci		dev_err(component->dev, "Failed to update DAC registers\n");
1488c2ecf20Sopenharmony_ci		return ret;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return ret;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/*
1558c2ecf20Sopenharmony_ci * DAC
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistatic int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	/* Sanity check only */
1608c2ecf20Sopenharmony_ci	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
1618c2ecf20Sopenharmony_ci		dev_err(dai->component->dev,
1628c2ecf20Sopenharmony_ci			"%s: ERROR: Unsupporter master mask 0x%x\n",
1638c2ecf20Sopenharmony_ci			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
1648c2ecf20Sopenharmony_ci		return -EINVAL;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
1718c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
1728c2ecf20Sopenharmony_ci			     STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
1738c2ecf20Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC standby",  "dac_p", STIH407_AUDIO_DAC_CTRL,
1748c2ecf20Sopenharmony_ci			 STIH407_DAC_STANDBY, 1),
1758c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("DAC Output"),
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route stih407_sas_route[] = {
1798c2ecf20Sopenharmony_ci	{"DAC Output", NULL, "DAC standby ana"},
1808c2ecf20Sopenharmony_ci	{"DAC standby ana", NULL, "DAC standby"},
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (mute) {
1898c2ecf20Sopenharmony_ci		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
1908c2ecf20Sopenharmony_ci					    STIH407_DAC_SOFTMUTE_MASK,
1918c2ecf20Sopenharmony_ci					    STIH407_DAC_SOFTMUTE_MASK);
1928c2ecf20Sopenharmony_ci	} else {
1938c2ecf20Sopenharmony_ci		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
1948c2ecf20Sopenharmony_ci					    STIH407_DAC_SOFTMUTE_MASK,
1958c2ecf20Sopenharmony_ci					    0);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/*
2008c2ecf20Sopenharmony_ci * SPDIF
2018c2ecf20Sopenharmony_ci */
2028c2ecf20Sopenharmony_cistatic int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
2038c2ecf20Sopenharmony_ci				 unsigned int fmt)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
2068c2ecf20Sopenharmony_ci		dev_err(dai->component->dev,
2078c2ecf20Sopenharmony_ci			"%s: ERROR: Unsupporter master mask 0x%x\n",
2088c2ecf20Sopenharmony_ci			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
2098c2ecf20Sopenharmony_ci		return -EINVAL;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/*
2168c2ecf20Sopenharmony_ci * sti_sas_spdif_trigger:
2178c2ecf20Sopenharmony_ci * Trigger function is used to ensure that BiPhase Formater is disabled
2188c2ecf20Sopenharmony_ci * before CPU dai is stopped.
2198c2ecf20Sopenharmony_ci * This is mandatory to avoid that BPF is stalled
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_cistatic int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
2228c2ecf20Sopenharmony_ci				 struct snd_soc_dai *dai)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	switch (cmd) {
2278c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
2288c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2298c2ecf20Sopenharmony_ci		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
2308c2ecf20Sopenharmony_ci					    SPDIF_BIPHASE_ENABLE_MASK,
2318c2ecf20Sopenharmony_ci					    SPDIF_BIPHASE_ENABLE_MASK);
2328c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
2338c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2348c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
2358c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
2368c2ecf20Sopenharmony_ci		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
2378c2ecf20Sopenharmony_ci					    SPDIF_BIPHASE_ENABLE_MASK,
2388c2ecf20Sopenharmony_ci					    0);
2398c2ecf20Sopenharmony_ci	default:
2408c2ecf20Sopenharmony_ci		return -EINVAL;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	if (reg == STIH407_AUDIO_GLUE_CTRL)
2478c2ecf20Sopenharmony_ci		return true;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return false;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/*
2538c2ecf20Sopenharmony_ci * CODEC DAIS
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/*
2578c2ecf20Sopenharmony_ci * sti_sas_set_sysclk:
2588c2ecf20Sopenharmony_ci * get MCLK input frequency to check that MCLK-FS ratio is coherent
2598c2ecf20Sopenharmony_ci */
2608c2ecf20Sopenharmony_cistatic int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
2618c2ecf20Sopenharmony_ci			      unsigned int freq, int dir)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2648c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (dir == SND_SOC_CLOCK_OUT)
2678c2ecf20Sopenharmony_ci		return 0;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (clk_id != 0)
2708c2ecf20Sopenharmony_ci		return -EINVAL;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	switch (dai->id) {
2738c2ecf20Sopenharmony_ci	case STI_SAS_DAI_SPDIF_OUT:
2748c2ecf20Sopenharmony_ci		drvdata->spdif.mclk = freq;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	case STI_SAS_DAI_ANALOG_OUT:
2788c2ecf20Sopenharmony_ci		drvdata->dac.mclk = freq;
2798c2ecf20Sopenharmony_ci		break;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int sti_sas_prepare(struct snd_pcm_substream *substream,
2868c2ecf20Sopenharmony_ci			   struct snd_soc_dai *dai)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2898c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
2908c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	switch (dai->id) {
2938c2ecf20Sopenharmony_ci	case STI_SAS_DAI_SPDIF_OUT:
2948c2ecf20Sopenharmony_ci		if ((drvdata->spdif.mclk / runtime->rate) != 128) {
2958c2ecf20Sopenharmony_ci			dev_err(component->dev, "unexpected mclk-fs ratio\n");
2968c2ecf20Sopenharmony_ci			return -EINVAL;
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	case STI_SAS_DAI_ANALOG_OUT:
3008c2ecf20Sopenharmony_ci		if ((drvdata->dac.mclk / runtime->rate) != 256) {
3018c2ecf20Sopenharmony_ci			dev_err(component->dev, "unexpected mclk-fs ratio\n");
3028c2ecf20Sopenharmony_ci			return -EINVAL;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops stih407_dac_ops = {
3118c2ecf20Sopenharmony_ci	.set_fmt = sti_sas_dac_set_fmt,
3128c2ecf20Sopenharmony_ci	.mute_stream = stih407_sas_dac_mute,
3138c2ecf20Sopenharmony_ci	.prepare = sti_sas_prepare,
3148c2ecf20Sopenharmony_ci	.set_sysclk = sti_sas_set_sysclk,
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic const struct regmap_config stih407_sas_regmap = {
3188c2ecf20Sopenharmony_ci	.reg_bits = 32,
3198c2ecf20Sopenharmony_ci	.val_bits = 32,
3208c2ecf20Sopenharmony_ci	.fast_io = true,
3218c2ecf20Sopenharmony_ci	.max_register = STIH407_AUDIO_DAC_CTRL,
3228c2ecf20Sopenharmony_ci	.reg_defaults = stih407_sas_reg_defaults,
3238c2ecf20Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
3248c2ecf20Sopenharmony_ci	.volatile_reg = sti_sas_volatile_register,
3258c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
3268c2ecf20Sopenharmony_ci	.reg_read = sti_sas_read_reg,
3278c2ecf20Sopenharmony_ci	.reg_write = sti_sas_write_reg,
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic const struct sti_sas_dev_data stih407_data = {
3318c2ecf20Sopenharmony_ci	.regmap = &stih407_sas_regmap,
3328c2ecf20Sopenharmony_ci	.dac_ops = &stih407_dac_ops,
3338c2ecf20Sopenharmony_ci	.dapm_widgets = stih407_sas_dapm_widgets,
3348c2ecf20Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
3358c2ecf20Sopenharmony_ci	.dapm_routes =	stih407_sas_route,
3368c2ecf20Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver sti_sas_dai[] = {
3408c2ecf20Sopenharmony_ci	{
3418c2ecf20Sopenharmony_ci		.name = "sas-dai-spdif-out",
3428c2ecf20Sopenharmony_ci		.id = STI_SAS_DAI_SPDIF_OUT,
3438c2ecf20Sopenharmony_ci		.playback = {
3448c2ecf20Sopenharmony_ci			.stream_name = "spdif_p",
3458c2ecf20Sopenharmony_ci			.channels_min = 2,
3468c2ecf20Sopenharmony_ci			.channels_max = 2,
3478c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
3488c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
3498c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
3508c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_192000,
3518c2ecf20Sopenharmony_ci			.formats = SNDRV_PCM_FMTBIT_S16_LE |
3528c2ecf20Sopenharmony_ci				   SNDRV_PCM_FMTBIT_S32_LE,
3538c2ecf20Sopenharmony_ci		},
3548c2ecf20Sopenharmony_ci		.ops = (struct snd_soc_dai_ops[]) {
3558c2ecf20Sopenharmony_ci			{
3568c2ecf20Sopenharmony_ci				.set_fmt = sti_sas_spdif_set_fmt,
3578c2ecf20Sopenharmony_ci				.trigger = sti_sas_spdif_trigger,
3588c2ecf20Sopenharmony_ci				.set_sysclk = sti_sas_set_sysclk,
3598c2ecf20Sopenharmony_ci				.prepare = sti_sas_prepare,
3608c2ecf20Sopenharmony_ci			}
3618c2ecf20Sopenharmony_ci		},
3628c2ecf20Sopenharmony_ci	},
3638c2ecf20Sopenharmony_ci	{
3648c2ecf20Sopenharmony_ci		.name = "sas-dai-dac",
3658c2ecf20Sopenharmony_ci		.id = STI_SAS_DAI_ANALOG_OUT,
3668c2ecf20Sopenharmony_ci		.playback = {
3678c2ecf20Sopenharmony_ci			.stream_name = "dac_p",
3688c2ecf20Sopenharmony_ci			.channels_min = 2,
3698c2ecf20Sopenharmony_ci			.channels_max = 2,
3708c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_48000,
3718c2ecf20Sopenharmony_ci			.formats = SNDRV_PCM_FMTBIT_S16_LE |
3728c2ecf20Sopenharmony_ci				   SNDRV_PCM_FMTBIT_S32_LE,
3738c2ecf20Sopenharmony_ci		},
3748c2ecf20Sopenharmony_ci	},
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
3788c2ecf20Sopenharmony_cistatic int sti_sas_resume(struct snd_soc_component *component)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return sti_sas_init_sas_registers(component, drvdata);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci#else
3858c2ecf20Sopenharmony_ci#define sti_sas_resume NULL
3868c2ecf20Sopenharmony_ci#endif
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic int sti_sas_component_probe(struct snd_soc_component *component)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
3918c2ecf20Sopenharmony_ci	int ret;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	ret = sti_sas_init_sas_registers(component, drvdata);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	return ret;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic struct snd_soc_component_driver sti_sas_driver = {
3998c2ecf20Sopenharmony_ci	.probe			= sti_sas_component_probe,
4008c2ecf20Sopenharmony_ci	.resume			= sti_sas_resume,
4018c2ecf20Sopenharmony_ci	.idle_bias_on		= 1,
4028c2ecf20Sopenharmony_ci	.use_pmdown_time	= 1,
4038c2ecf20Sopenharmony_ci	.endianness		= 1,
4048c2ecf20Sopenharmony_ci	.non_legacy_dai_naming	= 1,
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic const struct of_device_id sti_sas_dev_match[] = {
4088c2ecf20Sopenharmony_ci	{
4098c2ecf20Sopenharmony_ci		.compatible = "st,stih407-sas-codec",
4108c2ecf20Sopenharmony_ci		.data = &stih407_data,
4118c2ecf20Sopenharmony_ci	},
4128c2ecf20Sopenharmony_ci	{},
4138c2ecf20Sopenharmony_ci};
4148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sti_sas_dev_match);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int sti_sas_driver_probe(struct platform_device *pdev)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct device_node *pnode = pdev->dev.of_node;
4198c2ecf20Sopenharmony_ci	struct sti_sas_data *drvdata;
4208c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/* Allocate device structure */
4238c2ecf20Sopenharmony_ci	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
4248c2ecf20Sopenharmony_ci			       GFP_KERNEL);
4258c2ecf20Sopenharmony_ci	if (!drvdata)
4268c2ecf20Sopenharmony_ci		return -ENOMEM;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* Populate data structure depending on compatibility */
4298c2ecf20Sopenharmony_ci	of_id = of_match_node(sti_sas_dev_match, pnode);
4308c2ecf20Sopenharmony_ci	if (!of_id->data) {
4318c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "data associated to device is missing\n");
4328c2ecf20Sopenharmony_ci		return -EINVAL;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* Initialise device structure */
4388c2ecf20Sopenharmony_ci	drvdata->dev = &pdev->dev;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/* Request the DAC & SPDIF registers memory region */
4418c2ecf20Sopenharmony_ci	drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
4428c2ecf20Sopenharmony_ci						    drvdata->dev_data->regmap);
4438c2ecf20Sopenharmony_ci	if (IS_ERR(drvdata->dac.virt_regmap)) {
4448c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "audio registers not enabled\n");
4458c2ecf20Sopenharmony_ci		return PTR_ERR(drvdata->dac.virt_regmap);
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Request the syscon region */
4498c2ecf20Sopenharmony_ci	drvdata->dac.regmap =
4508c2ecf20Sopenharmony_ci		syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
4518c2ecf20Sopenharmony_ci	if (IS_ERR(drvdata->dac.regmap)) {
4528c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "syscon registers not available\n");
4538c2ecf20Sopenharmony_ci		return PTR_ERR(drvdata->dac.regmap);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci	drvdata->spdif.regmap = drvdata->dac.regmap;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* Set dapms*/
4608c2ecf20Sopenharmony_ci	sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
4618c2ecf20Sopenharmony_ci	sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
4648c2ecf20Sopenharmony_ci	sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* Store context */
4678c2ecf20Sopenharmony_ci	dev_set_drvdata(&pdev->dev, drvdata);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
4708c2ecf20Sopenharmony_ci					sti_sas_dai,
4718c2ecf20Sopenharmony_ci					ARRAY_SIZE(sti_sas_dai));
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic struct platform_driver sti_sas_platform_driver = {
4758c2ecf20Sopenharmony_ci	.driver = {
4768c2ecf20Sopenharmony_ci		.name = "sti-sas-codec",
4778c2ecf20Sopenharmony_ci		.of_match_table = sti_sas_dev_match,
4788c2ecf20Sopenharmony_ci	},
4798c2ecf20Sopenharmony_ci	.probe = sti_sas_driver_probe,
4808c2ecf20Sopenharmony_ci};
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cimodule_platform_driver(sti_sas_platform_driver);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
4858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arnaud.pouliquen@st.com");
4868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
487