linux/sound/soc/codecs/src4xxx.c

// SPDX-License-Identifier: GPL-2.0
//
// TI SRC4xxx Audio Codec driver
//
// Copyright 2021-2022 Deqx Pty Ltd
// Author: Matt Flax <[email protected]>

#include <linux/module.h>

#include <sound/soc.h>
#include <sound/tlv.h>

#include "src4xxx.h"

struct src4xxx {};

enum {};

/* SRC attenuation */
static const DECLARE_TLV_DB_SCALE(src_tlv, -12750, 50, 0);

static const struct snd_kcontrol_new src4xxx_controls[] =;

/* I2S port control */
static const char * const port_out_src_text[] =;
static SOC_ENUM_SINGLE_DECL(porta_out_src_enum, SRC4XXX_PORTA_CTL_03, 4,
	port_out_src_text);
static SOC_ENUM_SINGLE_DECL(portb_out_src_enum, SRC4XXX_PORTB_CTL_05, 4,
	port_out_src_text);
static const struct snd_kcontrol_new porta_out_control =;
static const struct snd_kcontrol_new portb_out_control =;

/* Digital audio transmitter control */
static const char * const dit_mux_text[] =;
static SOC_ENUM_SINGLE_DECL(dit_mux_enum, SRC4XXX_TX_CTL_07, 3, dit_mux_text);
static const struct snd_kcontrol_new dit_mux_control =;

/* SRC control */
static const char * const src_in_text[] =;
static SOC_ENUM_SINGLE_DECL(src_in_enum, SRC4XXX_SCR_CTL_2D, 0, src_in_text);
static const struct snd_kcontrol_new src_in_control =;

/* DIR control */
static const char * const dir_in_text[] =;
static SOC_ENUM_SINGLE_DECL(dir_in_enum, SRC4XXX_RCV_CTL_0D, 0, dir_in_text);
static const struct snd_kcontrol_new dir_in_control =;

static const struct snd_soc_dapm_widget src4xxx_dapm_widgets[] =;

static const struct snd_soc_dapm_route src4xxx_audio_routes[] =;


static const struct snd_soc_component_driver src4xxx_driver =;

static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{}

static int src4xxx_set_mclk_hz(struct snd_soc_dai *codec_dai,
		int clk_id, unsigned int freq, int dir)
{}

static int src4xxx_hw_params(struct snd_pcm_substream *substream,
			struct snd_pcm_hw_params *params,
			struct snd_soc_dai *dai)
{
	struct snd_soc_component *component = dai->component;
	struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component);
	unsigned int mclk_div;
	int val, pj, jd, d;
	int reg;
	int ret;

	switch (dai->id) {
	case SRC4XXX_PORTB:
		reg = SRC4XXX_PORTB_CTL_06;
		break;
	default:
		reg = SRC4XXX_PORTA_CTL_04;
		break;
	}

	if (src4xxx->master[dai->id]) {
		mclk_div = src4xxx->mclk_hz/params_rate(params);
		if (src4xxx->mclk_hz != mclk_div*params_rate(params)) {
			dev_err(component->dev,
				"mclk %d / rate %d has a remainder.\n",
				src4xxx->mclk_hz, params_rate(params));
			return -EINVAL;
		}

		val = ((int)mclk_div - 128) / 128;
		if ((val < 0) | (val > 3)) {
			dev_err(component->dev,
				"div register setting %d is out of range\n",
				val);
			dev_err(component->dev,
				"unsupported sample rate %d Hz for the master clock of %d Hz\n",
				params_rate(params), src4xxx->mclk_hz);
			return -EINVAL;
		}

		/* set the TX DIV */
		ret = regmap_update_bits(src4xxx->regmap,
			SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK,
			val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
		if (ret) {
			dev_err(component->dev,
				"Couldn't set the TX's div register to %d << %d = 0x%x\n",
				val, SRC4XXX_TX_MCLK_DIV_SHIFT,
				val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
			return ret;
		}

		/* set the PLL for the digital receiver */
		switch (src4xxx->mclk_hz) {
		case 24576000:
			pj = 0x22;
			jd = 0x00;
			d = 0x00;
			break;
		case 22579200:
			pj = 0x22;
			jd = 0x1b;
			d = 0xa3;
			break;
		default:
			/* don't error out here,
			 * other parts of the chip are still functional
			 * Dummy initialize variables to avoid
			 * -Wsometimes-uninitialized from clang.
			 */
			dev_info(component->dev,
				"Couldn't set the RCV PLL as this master clock rate is unknown. Chosen regmap values may not match real world values.\n");
			pj = 0x0;
			jd = 0xff;
			d = 0xff;
			break;
		}
		ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj);
		if (ret < 0)
			dev_err(component->dev,
				"Failed to update PLL register 0x%x\n",
				SRC4XXX_RCV_PLL_0F);
		ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_10, jd);
		if (ret < 0)
			dev_err(component->dev,
				"Failed to update PLL register 0x%x\n",
				SRC4XXX_RCV_PLL_10);
		ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_11, d);
		if (ret < 0)
			dev_err(component->dev,
				"Failed to update PLL register 0x%x\n",
				SRC4XXX_RCV_PLL_11);

		ret = regmap_update_bits(src4xxx->regmap,
			SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK,
			val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
		if (ret < 0) {
			dev_err(component->dev,
				"Couldn't set the TX's div register to %d << %d = 0x%x\n",
				val, SRC4XXX_TX_MCLK_DIV_SHIFT,
				val<<SRC4XXX_TX_MCLK_DIV_SHIFT);
			return ret;
		}

		return regmap_update_bits(src4xxx->regmap, reg,
					SRC4XXX_MCLK_DIV_MASK, val);
	} else {
		dev_info(dai->dev, "not setting up MCLK as not master\n");
	}

	return 0;
};

static const struct snd_soc_dai_ops src4xxx_dai_ops =;

#define SRC4XXX_FORMATS
#define SRC4XXX_RATES

static struct snd_soc_dai_driver src4xxx_dai_driver[] =;

static const struct reg_default src4xxx_reg_defaults[] =;

int src4xxx_probe(struct device *dev, struct regmap *regmap,
			void (*switch_mode)(struct device *dev))
{}
EXPORT_SYMBOL_GPL();

static bool src4xxx_volatile_register(struct device *dev, unsigned int reg)
{}

const struct regmap_config src4xxx_regmap_config =;
EXPORT_SYMBOL_GPL();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();