brintos

brintos / linux-shallow public Read only

0
0
Text · 12.9 KiB · e721f57 Raw
497 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2//3// Copyright (c) 2018 BayLibre, SAS.4// Author: Jerome Brunet <jbrunet@baylibre.com>5 6#include <linux/bitfield.h>7#include <linux/clk.h>8#include <linux/module.h>9#include <linux/of_platform.h>10#include <linux/regmap.h>11#include <sound/soc.h>12#include <sound/soc-dai.h>13#include <sound/pcm_params.h>14 15#define SPDIFIN_CTRL0			0x0016#define  SPDIFIN_CTRL0_EN		BIT(31)17#define  SPDIFIN_CTRL0_RST_OUT		BIT(29)18#define  SPDIFIN_CTRL0_RST_IN		BIT(28)19#define  SPDIFIN_CTRL0_WIDTH_SEL	BIT(24)20#define  SPDIFIN_CTRL0_STATUS_CH_SHIFT	1121#define  SPDIFIN_CTRL0_STATUS_SEL	GENMASK(10, 8)22#define  SPDIFIN_CTRL0_SRC_SEL		GENMASK(5, 4)23#define  SPDIFIN_CTRL0_CHK_VALID	BIT(3)24#define SPDIFIN_CTRL1			0x0425#define  SPDIFIN_CTRL1_BASE_TIMER	GENMASK(19, 0)26#define  SPDIFIN_CTRL1_IRQ_MASK		GENMASK(27, 20)27#define SPDIFIN_CTRL2			0x0828#define  SPDIFIN_THRES_PER_REG		329#define  SPDIFIN_THRES_WIDTH		1030#define SPDIFIN_CTRL3			0x0c31#define SPDIFIN_CTRL4			0x1032#define  SPDIFIN_TIMER_PER_REG		433#define  SPDIFIN_TIMER_WIDTH		834#define SPDIFIN_CTRL5			0x1435#define SPDIFIN_CTRL6			0x1836#define SPDIFIN_STAT0			0x1c37#define  SPDIFIN_STAT0_MODE		GENMASK(30, 28)38#define  SPDIFIN_STAT0_MAXW		GENMASK(17, 8)39#define  SPDIFIN_STAT0_IRQ		GENMASK(7, 0)40#define  SPDIFIN_IRQ_MODE_CHANGED	BIT(2)41#define SPDIFIN_STAT1			0x2042#define SPDIFIN_STAT2			0x2443#define SPDIFIN_MUTE_VAL		0x2844 45#define SPDIFIN_MODE_NUM		746 47struct axg_spdifin_cfg {48	const unsigned int *mode_rates;49	unsigned int ref_rate;50};51 52struct axg_spdifin {53	const struct axg_spdifin_cfg *conf;54	struct regmap *map;55	struct clk *refclk;56	struct clk *pclk;57};58 59/*60 * TODO:61 * It would have been nice to check the actual rate against the sample rate62 * requested in hw_params(). Unfortunately, I was not able to make the mode63 * detection and IRQ work reliably:64 *65 * 1. IRQs are generated on mode change only, so there is no notification66 *    on transition between no signal and mode 0 (32kHz).67 * 2. Mode detection very often has glitches, and may detects the68 *    lowest or the highest mode before zeroing in on the actual mode.69 *70 * This makes calling snd_pcm_stop() difficult to get right. Even notifying71 * the kcontrol would be very unreliable at this point.72 * Let's keep things simple until the magic spell that makes this work is73 * found.74 */75 76static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv)77{78	unsigned int stat, mode, rate = 0;79 80	regmap_read(priv->map, SPDIFIN_STAT0, &stat);81	mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat);82 83	/*84	 * If max width is zero, we are not capturing anything.85	 * Also Sometimes, when the capture is on but there is no data,86	 * mode is SPDIFIN_MODE_NUM, but not always ...87	 */88	if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&89	    mode < SPDIFIN_MODE_NUM)90		rate = priv->conf->mode_rates[mode];91 92	return rate;93}94 95static int axg_spdifin_prepare(struct snd_pcm_substream *substream,96			       struct snd_soc_dai *dai)97{98	struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);99 100	/* Apply both reset */101	regmap_update_bits(priv->map, SPDIFIN_CTRL0,102			   SPDIFIN_CTRL0_RST_OUT |103			   SPDIFIN_CTRL0_RST_IN,104			   0);105 106	/* Clear out reset before in reset */107	regmap_update_bits(priv->map, SPDIFIN_CTRL0,108			   SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT);109	regmap_update_bits(priv->map, SPDIFIN_CTRL0,110			   SPDIFIN_CTRL0_RST_IN,  SPDIFIN_CTRL0_RST_IN);111 112	return 0;113}114 115static void axg_spdifin_write_mode_param(struct regmap *map, int mode,116					 unsigned int val,117					 unsigned int num_per_reg,118					 unsigned int base_reg,119					 unsigned int width)120{121	uint64_t offset = mode;122	unsigned int reg, shift, rem;123 124	rem = do_div(offset, num_per_reg);125 126	reg = offset * regmap_get_reg_stride(map) + base_reg;127	shift = width * (num_per_reg - 1 - rem);128 129	regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift,130			   val << shift);131}132 133static void axg_spdifin_write_timer(struct regmap *map, int mode,134				    unsigned int val)135{136	axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG,137				     SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH);138}139 140static void axg_spdifin_write_threshold(struct regmap *map, int mode,141					unsigned int val)142{143	axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG,144				     SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH);145}146 147static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv,148					   int mode,149					   unsigned int rate)150{151	/*152	 * Number of period of the reference clock during a period of the153	 * input signal reference clock154	 */155	return rate / (128 * priv->conf->mode_rates[mode]);156}157 158static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,159					  struct axg_spdifin *priv)160{161	unsigned int rate, t_next;162	int ret, i = SPDIFIN_MODE_NUM - 1;163 164	/* Set spdif input reference clock */165	ret = clk_set_rate(priv->refclk, priv->conf->ref_rate);166	if (ret) {167		dev_err(dai->dev, "reference clock rate set failed\n");168		return ret;169	}170 171	/*172	 * The rate actually set might be slightly different, get173	 * the actual rate for the following mode calculation174	 */175	rate = clk_get_rate(priv->refclk);176 177	/* HW will update mode every 1ms */178	regmap_update_bits(priv->map, SPDIFIN_CTRL1,179			   SPDIFIN_CTRL1_BASE_TIMER,180			   FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));181 182	/* Threshold based on the maximum width between two edges */183	regmap_update_bits(priv->map, SPDIFIN_CTRL0,184			   SPDIFIN_CTRL0_WIDTH_SEL, 0);185 186	/* Calculate the last timer which has no threshold */187	t_next = axg_spdifin_mode_timer(priv, i, rate);188	axg_spdifin_write_timer(priv->map, i, t_next);189 190	do {191		unsigned int t;192 193		i -= 1;194 195		/* Calculate the timer */196		t = axg_spdifin_mode_timer(priv, i, rate);197 198		/* Set the timer value */199		axg_spdifin_write_timer(priv->map, i, t);200 201		/* Set the threshold value */202		axg_spdifin_write_threshold(priv->map, i, 3 * (t + t_next));203 204		/* Save the current timer for the next threshold calculation */205		t_next = t;206 207	} while (i > 0);208 209	return 0;210}211 212static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)213{214	struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);215	int ret;216 217	ret = clk_prepare_enable(priv->pclk);218	if (ret) {219		dev_err(dai->dev, "failed to enable pclk\n");220		return ret;221	}222 223	ret = axg_spdifin_sample_mode_config(dai, priv);224	if (ret) {225		dev_err(dai->dev, "mode configuration failed\n");226		goto pclk_err;227	}228 229	ret = clk_prepare_enable(priv->refclk);230	if (ret) {231		dev_err(dai->dev,232			"failed to enable spdifin reference clock\n");233		goto pclk_err;234	}235 236	regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,237			   SPDIFIN_CTRL0_EN);238 239	return 0;240 241pclk_err:242	clk_disable_unprepare(priv->pclk);243	return ret;244}245 246static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)247{248	struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);249 250	regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);251	clk_disable_unprepare(priv->refclk);252	clk_disable_unprepare(priv->pclk);253	return 0;254}255 256static const struct snd_soc_dai_ops axg_spdifin_ops = {257	.probe		= axg_spdifin_dai_probe,258	.remove		= axg_spdifin_dai_remove,259	.prepare	= axg_spdifin_prepare,260};261 262static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol,263				   struct snd_ctl_elem_info *uinfo)264{265	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;266	uinfo->count = 1;267 268	return 0;269}270 271static int axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol,272				       struct snd_ctl_elem_value *ucontrol)273{274	int i;275 276	for (i = 0; i < 24; i++)277		ucontrol->value.iec958.status[i] = 0xff;278 279	return 0;280}281 282static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol,283				  struct snd_ctl_elem_value *ucontrol)284{285	struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);286	struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);287	int i, j;288 289	for (i = 0; i < 6; i++) {290		unsigned int val;291 292		regmap_update_bits(priv->map, SPDIFIN_CTRL0,293				   SPDIFIN_CTRL0_STATUS_SEL,294				   FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i));295 296		regmap_read(priv->map, SPDIFIN_STAT1, &val);297 298		for (j = 0; j < 4; j++) {299			unsigned int offset = i * 4 + j;300 301			ucontrol->value.iec958.status[offset] =302				(val >> (j * 8)) & 0xff;303		}304	}305 306	return 0;307}308 309#define AXG_SPDIFIN_IEC958_MASK						\310	{								\311		.access = SNDRV_CTL_ELEM_ACCESS_READ,			\312		.iface = SNDRV_CTL_ELEM_IFACE_PCM,			\313		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),	\314		.info = axg_spdifin_iec958_info,			\315		.get = axg_spdifin_get_status_mask,			\316	}317 318#define AXG_SPDIFIN_IEC958_STATUS					\319	{								\320		.access = (SNDRV_CTL_ELEM_ACCESS_READ |			\321			   SNDRV_CTL_ELEM_ACCESS_VOLATILE),		\322		.iface = SNDRV_CTL_ELEM_IFACE_PCM,			\323		.name =	SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE),	\324		.info = axg_spdifin_iec958_info,			\325		.get = axg_spdifin_get_status,				\326	}327 328static const char * const spdifin_chsts_src_texts[] = {329	"A", "B",330};331 332static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0,333			    SPDIFIN_CTRL0_STATUS_CH_SHIFT,334			    spdifin_chsts_src_texts);335 336static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol,337				      struct snd_ctl_elem_info *uinfo)338{339	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;340	uinfo->count = 1;341	uinfo->value.integer.min = 0;342	uinfo->value.integer.max = 192000;343 344	return 0;345}346 347static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol,348				     struct snd_ctl_elem_value *ucontrol)349{350	struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);351	struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);352 353	ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv);354 355	return 0;356}357 358#define AXG_SPDIFIN_LOCK_RATE(xname)				\359	{							\360		.iface = SNDRV_CTL_ELEM_IFACE_PCM,		\361		.access = (SNDRV_CTL_ELEM_ACCESS_READ |		\362			   SNDRV_CTL_ELEM_ACCESS_VOLATILE),	\363		.get = axg_spdifin_rate_lock_get,		\364		.info = axg_spdifin_rate_lock_info,		\365		.name = xname,					\366	}367 368static const struct snd_kcontrol_new axg_spdifin_controls[] = {369	AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"),370	SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1),371	SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src",372		 axg_spdifin_chsts_src_enum),373	AXG_SPDIFIN_IEC958_MASK,374	AXG_SPDIFIN_IEC958_STATUS,375};376 377static const struct snd_soc_component_driver axg_spdifin_component_drv = {378	.controls		= axg_spdifin_controls,379	.num_controls		= ARRAY_SIZE(axg_spdifin_controls),380	.legacy_dai_naming	= 1,381};382 383static const struct regmap_config axg_spdifin_regmap_cfg = {384	.reg_bits	= 32,385	.val_bits	= 32,386	.reg_stride	= 4,387	.max_register	= SPDIFIN_MUTE_VAL,388};389 390static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = {391	32000, 44100, 48000, 88200, 96000, 176400, 192000,392};393 394static const struct axg_spdifin_cfg axg_cfg = {395	.mode_rates = axg_spdifin_mode_rates,396	.ref_rate = 333333333,397};398 399static const struct of_device_id axg_spdifin_of_match[] = {400	{401		.compatible = "amlogic,axg-spdifin",402		.data = &axg_cfg,403	}, {}404};405MODULE_DEVICE_TABLE(of, axg_spdifin_of_match);406 407static struct snd_soc_dai_driver *408axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)409{410	struct snd_soc_dai_driver *drv;411	int i;412 413	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);414	if (!drv)415		return ERR_PTR(-ENOMEM);416 417	drv->name = "SPDIF Input";418	drv->ops = &axg_spdifin_ops;419	drv->capture.stream_name = "Capture";420	drv->capture.channels_min = 1;421	drv->capture.channels_max = 2;422	drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;423 424	for (i = 0; i < SPDIFIN_MODE_NUM; i++) {425		unsigned int rb =426			snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]);427 428		if (rb == SNDRV_PCM_RATE_KNOT)429			return ERR_PTR(-EINVAL);430 431		drv->capture.rates |= rb;432	}433 434	return drv;435}436 437static int axg_spdifin_probe(struct platform_device *pdev)438{439	struct device *dev = &pdev->dev;440	struct axg_spdifin *priv;441	struct snd_soc_dai_driver *dai_drv;442	void __iomem *regs;443 444	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);445	if (!priv)446		return -ENOMEM;447	platform_set_drvdata(pdev, priv);448 449	priv->conf = of_device_get_match_data(dev);450	if (!priv->conf) {451		dev_err(dev, "failed to match device\n");452		return -ENODEV;453	}454 455	regs = devm_platform_ioremap_resource(pdev, 0);456	if (IS_ERR(regs))457		return PTR_ERR(regs);458 459	priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg);460	if (IS_ERR(priv->map)) {461		dev_err(dev, "failed to init regmap: %ld\n",462			PTR_ERR(priv->map));463		return PTR_ERR(priv->map);464	}465 466	priv->pclk = devm_clk_get(dev, "pclk");467	if (IS_ERR(priv->pclk))468		return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n");469 470	priv->refclk = devm_clk_get(dev, "refclk");471	if (IS_ERR(priv->refclk))472		return dev_err_probe(dev, PTR_ERR(priv->refclk), "failed to get mclk\n");473 474	dai_drv = axg_spdifin_get_dai_drv(dev, priv);475	if (IS_ERR(dai_drv)) {476		dev_err(dev, "failed to get dai driver: %ld\n",477			PTR_ERR(dai_drv));478		return PTR_ERR(dai_drv);479	}480 481	return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv,482					       dai_drv, 1);483}484 485static struct platform_driver axg_spdifin_pdrv = {486	.probe = axg_spdifin_probe,487	.driver = {488		.name = "axg-spdifin",489		.of_match_table = axg_spdifin_of_match,490	},491};492module_platform_driver(axg_spdifin_pdrv);493 494MODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver");495MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");496MODULE_LICENSE("GPL v2");497