Unverified Commit aa0f18d7 authored by Steven Eckhoff's avatar Steven Eckhoff Committed by Mark Brown
Browse files

ASoC: TSCS42xx: Add CCF support to get sysclk



The TSCS42xx relies on set_sysclk to get a unique clock id and rate,
which prevents it from being used with the simple-card.

Remove set_sysclk callback
Add CCF support to get clock id and rate
Add clocks and clock-names to device tree binding

Signed-off-by: default avatarSteven Eckhoff <steven.eckhoff.opensource@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7ab5ba47
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -8,9 +8,15 @@ Required Properties:
	- reg : 	<0x71> for analog mic
			<0x69> for digital mic

	- clock-names:	Must one of  the following "mclk1", "xtal", "mclk2"

	- clocks:	phandle of the clock that provides the codec sysclk

Example:

wookie: codec@69 {
	compatible = "tempo,tscs42A2";
	reg = <0x69>;
	clock-names = "xtal";
	clocks = <&audio_xtal>;
};
+68 −36
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -40,6 +41,9 @@ struct tscs42xx {
	struct mutex pll_lock;

	struct regmap *regmap;

	struct clk *sysclk;
	int sysclk_src_id;
};

struct coeff_ram_ctl {
@@ -1251,13 +1255,46 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
	return 0;
}

static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
	int clk_id, unsigned int freq, int dir)
static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
	.hw_params	= tscs42xx_hw_params,
	.mute_stream	= tscs42xx_mute_stream,
	.set_fmt	= tscs42xx_set_dai_fmt,
	.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
};

static int part_is_valid(struct tscs42xx *tscs42xx)
{
	struct snd_soc_component *component = codec_dai->component;
	int val;
	int ret;
	unsigned int reg;

	ret = regmap_read(tscs42xx->regmap, R_DEVIDH, &reg);
	if (ret < 0)
		return ret;

	switch (clk_id) {
	val = reg << 8;
	ret = regmap_read(tscs42xx->regmap, R_DEVIDL, &reg);
	if (ret < 0)
		return ret;

	val |= reg;

	switch (val) {
	case 0x4A74:
	case 0x4A73:
		return true;
	default:
		return false;
	};
}

static int set_sysclk(struct snd_soc_component *component)
{
	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
	unsigned long freq;
	int ret;

	switch (tscs42xx->sysclk_src_id) {
	case TSCS42XX_PLL_SRC_XTAL:
	case TSCS42XX_PLL_SRC_MCLK1:
		ret = snd_soc_component_write(component, R_PLLREFSEL,
@@ -1285,6 +1322,7 @@ static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
		return -EINVAL;
	}

	freq = clk_get_rate(tscs42xx->sysclk);
	ret = set_pll_ctl_from_input_freq(component, freq);
	if (ret < 0) {
		dev_err(component->dev,
@@ -1295,41 +1333,13 @@ static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
	return 0;
}

static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
	.hw_params	= tscs42xx_hw_params,
	.mute_stream	= tscs42xx_mute_stream,
	.set_fmt	= tscs42xx_set_dai_fmt,
	.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
	.set_sysclk	= tscs42xx_set_dai_sysclk,
};

static int part_is_valid(struct tscs42xx *tscs42xx)
static int tscs42xx_probe(struct snd_soc_component *component)
{
	int val;
	int ret;
	unsigned int reg;

	ret = regmap_read(tscs42xx->regmap, R_DEVIDH, &reg);
	if (ret < 0)
		return ret;

	val = reg << 8;
	ret = regmap_read(tscs42xx->regmap, R_DEVIDL, &reg);
	if (ret < 0)
		return ret;

	val |= reg;

	switch (val) {
	case 0x4A74:
	case 0x4A73:
		return true;
	default:
		return false;
	};
	return set_sysclk(component);
}

static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
	.probe			= tscs42xx_probe,
	.dapm_widgets		= tscs42xx_dapm_widgets,
	.num_dapm_widgets	= ARRAY_SIZE(tscs42xx_dapm_widgets),
	.dapm_routes		= tscs42xx_intercon,
@@ -1387,11 +1397,15 @@ static const struct reg_sequence tscs42xx_patch[] = {
	{ R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED },
};

static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = {
	"xtal", "mclk1", "mclk2"};

static int tscs42xx_i2c_probe(struct i2c_client *i2c,
		const struct i2c_device_id *id)
{
	struct tscs42xx *tscs42xx;
	int ret = 0;
	int src;
	int ret;

	tscs42xx = devm_kzalloc(&i2c->dev, sizeof(*tscs42xx), GFP_KERNEL);
	if (!tscs42xx) {
@@ -1402,6 +1416,24 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
	}
	i2c_set_clientdata(i2c, tscs42xx);

	for (src = TSCS42XX_PLL_SRC_XTAL; src < TSCS42XX_PLL_SRC_CNT; src++) {
		tscs42xx->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
		if (!IS_ERR(tscs42xx->sysclk)) {
			break;
		} else if (PTR_ERR(tscs42xx->sysclk) != -ENOENT) {
			ret = PTR_ERR(tscs42xx->sysclk);
			dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
			return ret;
		}
	}
	if (src == TSCS42XX_PLL_SRC_CNT) {
		ret = -EINVAL;
		dev_err(&i2c->dev, "Failed to get a valid clock name (%d)\n",
				ret);
		return ret;
	}
	tscs42xx->sysclk_src_id = src;

	tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap);
	if (IS_ERR(tscs42xx->regmap)) {
		ret = PTR_ERR(tscs42xx->regmap);
+1 −1
Original line number Diff line number Diff line
@@ -7,10 +7,10 @@
#define __WOOKIE_H__

enum {
	TSCS42XX_PLL_SRC_NONE,
	TSCS42XX_PLL_SRC_XTAL,
	TSCS42XX_PLL_SRC_MCLK1,
	TSCS42XX_PLL_SRC_MCLK2,
	TSCS42XX_PLL_SRC_CNT,
};

#define R_HPVOLL        0x0