brintos

brintos / linux-shallow public Read only

0
0
Text · 30.5 KiB · c9e7d40 Raw
1189 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Apple SoCs MCA driver4//5// Copyright (C) The Asahi Linux Contributors6//7// The MCA peripheral is made up of a number of identical units called clusters.8// Each cluster has its separate clock parent, SYNC signal generator, carries9// four SERDES units and has a dedicated I2S port on the SoC's periphery.10//11// The clusters can operate independently, or can be combined together in a12// configurable manner. We mostly treat them as self-contained independent13// units and don't configure any cross-cluster connections except for the I2S14// ports. The I2S ports can be routed to any of the clusters (irrespective15// of their native cluster). We map this onto ASoC's (DPCM) notion of backend16// and frontend DAIs. The 'cluster guts' are frontends which are dynamically17// routed to backend I2S ports.18//19// DAI references in devicetree are resolved to backends. The routing between20// frontends and backends is determined by the machine driver in the DAPM paths21// it supplies.22 23#include <linux/bitfield.h>24#include <linux/clk.h>25#include <linux/dma-mapping.h>26#include <linux/init.h>27#include <linux/kernel.h>28#include <linux/module.h>29#include <linux/of.h>30#include <linux/of_clk.h>31#include <linux/of_dma.h>32#include <linux/platform_device.h>33#include <linux/pm_domain.h>34#include <linux/regmap.h>35#include <linux/reset.h>36#include <linux/slab.h>37 38#include <sound/core.h>39#include <sound/pcm.h>40#include <sound/pcm_params.h>41#include <sound/soc.h>42#include <sound/dmaengine_pcm.h>43 44#define USE_RXB_FOR_CAPTURE45 46/* Relative to cluster base */47#define REG_STATUS		0x048#define STATUS_MCLK_EN		BIT(0)49#define REG_MCLK_CONF		0x450#define MCLK_CONF_DIV		GENMASK(11, 8)51 52#define REG_SYNCGEN_STATUS	0x10053#define SYNCGEN_STATUS_EN	BIT(0)54#define REG_SYNCGEN_MCLK_SEL	0x10455#define SYNCGEN_MCLK_SEL	GENMASK(3, 0)56#define REG_SYNCGEN_HI_PERIOD	0x10857#define REG_SYNCGEN_LO_PERIOD	0x10c58 59#define REG_PORT_ENABLES	0x60060#define PORT_ENABLES_CLOCKS	GENMASK(2, 1)61#define PORT_ENABLES_TX_DATA	BIT(3)62#define REG_PORT_CLOCK_SEL	0x60463#define PORT_CLOCK_SEL		GENMASK(11, 8)64#define REG_PORT_DATA_SEL	0x60865#define PORT_DATA_SEL_TXA(cl)	(1 << ((cl)*2))66#define PORT_DATA_SEL_TXB(cl)	(2 << ((cl)*2))67 68#define REG_INTSTATE		0x70069#define REG_INTMASK		0x70470 71/* Bases of serdes units (relative to cluster) */72#define CLUSTER_RXA_OFF	0x20073#define CLUSTER_TXA_OFF	0x30074#define CLUSTER_RXB_OFF	0x40075#define CLUSTER_TXB_OFF	0x50076 77#define CLUSTER_TX_OFF	CLUSTER_TXA_OFF78 79#ifndef USE_RXB_FOR_CAPTURE80#define CLUSTER_RX_OFF	CLUSTER_RXA_OFF81#else82#define CLUSTER_RX_OFF	CLUSTER_RXB_OFF83#endif84 85/* Relative to serdes unit base */86#define REG_SERDES_STATUS	0x0087#define SERDES_STATUS_EN	BIT(0)88#define SERDES_STATUS_RST	BIT(1)89#define REG_TX_SERDES_CONF	0x0490#define REG_RX_SERDES_CONF	0x0891#define SERDES_CONF_NCHANS	GENMASK(3, 0)92#define SERDES_CONF_WIDTH_MASK	GENMASK(8, 4)93#define SERDES_CONF_WIDTH_16BIT 0x4094#define SERDES_CONF_WIDTH_20BIT 0x8095#define SERDES_CONF_WIDTH_24BIT 0xc096#define SERDES_CONF_WIDTH_32BIT 0x10097#define SERDES_CONF_BCLK_POL	0x40098#define SERDES_CONF_LSB_FIRST	0x80099#define SERDES_CONF_UNK1	BIT(12)100#define SERDES_CONF_UNK2	BIT(13)101#define SERDES_CONF_UNK3	BIT(14)102#define SERDES_CONF_NO_DATA_FEEDBACK	BIT(15)103#define SERDES_CONF_SYNC_SEL	GENMASK(18, 16)104#define REG_TX_SERDES_BITSTART	0x08105#define REG_RX_SERDES_BITSTART	0x0c106#define REG_TX_SERDES_SLOTMASK	0x0c107#define REG_RX_SERDES_SLOTMASK	0x10108#define REG_RX_SERDES_PORT	0x04109 110/* Relative to switch base */111#define REG_DMA_ADAPTER_A(cl)	(0x8000 * (cl))112#define REG_DMA_ADAPTER_B(cl)	(0x8000 * (cl) + 0x4000)113#define DMA_ADAPTER_TX_LSB_PAD	GENMASK(4, 0)114#define DMA_ADAPTER_TX_NCHANS	GENMASK(6, 5)115#define DMA_ADAPTER_RX_MSB_PAD	GENMASK(12, 8)116#define DMA_ADAPTER_RX_NCHANS	GENMASK(14, 13)117#define DMA_ADAPTER_NCHANS	GENMASK(22, 20)118 119#define SWITCH_STRIDE	0x8000120#define CLUSTER_STRIDE	0x4000121 122#define MAX_NCLUSTERS	6123 124#define APPLE_MCA_FMTBITS (SNDRV_PCM_FMTBIT_S16_LE | \125			   SNDRV_PCM_FMTBIT_S24_LE | \126			   SNDRV_PCM_FMTBIT_S32_LE)127 128struct mca_cluster {129	int no;130	__iomem void *base;131	struct mca_data *host;132	struct device *pd_dev;133	struct clk *clk_parent;134	struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];135 136	bool port_started[SNDRV_PCM_STREAM_LAST + 1];137	int port_driver; /* The cluster driving this cluster's port */138 139	bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1];140	struct device_link *pd_link;141 142	unsigned int bclk_ratio;143 144	/* Masks etc. picked up via the set_tdm_slot method */145	int tdm_slots;146	int tdm_slot_width;147	unsigned int tdm_tx_mask;148	unsigned int tdm_rx_mask;149};150 151struct mca_data {152	struct device *dev;153 154	__iomem void *switch_base;155 156	struct device *pd_dev;157	struct reset_control *rstc;158	struct device_link *pd_link;159 160	/* Mutex for accessing port_driver of foreign clusters */161	struct mutex port_mutex;162 163	int nclusters;164	struct mca_cluster clusters[] __counted_by(nclusters);165};166 167static void mca_modify(struct mca_cluster *cl, int regoffset, u32 mask, u32 val)168{169	__iomem void *ptr = cl->base + regoffset;170	u32 newval;171 172	newval = (val & mask) | (readl_relaxed(ptr) & ~mask);173	writel_relaxed(newval, ptr);174}175 176/*177 * Get the cluster of FE or BE DAI178 */179static struct mca_cluster *mca_dai_to_cluster(struct snd_soc_dai *dai)180{181	struct mca_data *mca = snd_soc_dai_get_drvdata(dai);182	/*183	 * FE DAIs are         0 ... nclusters - 1184	 * BE DAIs are nclusters ... 2*nclusters - 1185	 */186	int cluster_no = dai->id % mca->nclusters;187 188	return &mca->clusters[cluster_no];189}190 191/* called before PCM trigger */192static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,193				 struct snd_soc_dai *dai)194{195	struct mca_cluster *cl = mca_dai_to_cluster(dai);196	bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;197	int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF;198	int serdes_conf =199		serdes_unit + (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF);200 201	switch (cmd) {202	case SNDRV_PCM_TRIGGER_START:203	case SNDRV_PCM_TRIGGER_RESUME:204	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:205		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,206			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));207		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,208			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 7));209		mca_modify(cl, serdes_unit + REG_SERDES_STATUS,210			   SERDES_STATUS_EN | SERDES_STATUS_RST,211			   SERDES_STATUS_RST);212		/*213		 * Experiments suggest that it takes at most ~1 us214		 * for the bit to clear, so wait 2 us for good measure.215		 */216		udelay(2);217		WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &218			SERDES_STATUS_RST);219		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,220			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));221		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,222			   FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));223		break;224	default:225		break;226	}227}228 229static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,230			  struct snd_soc_dai *dai)231{232	struct mca_cluster *cl = mca_dai_to_cluster(dai);233	bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;234	int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF;235 236	switch (cmd) {237	case SNDRV_PCM_TRIGGER_START:238	case SNDRV_PCM_TRIGGER_RESUME:239	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:240		mca_modify(cl, serdes_unit + REG_SERDES_STATUS,241			   SERDES_STATUS_EN | SERDES_STATUS_RST,242			   SERDES_STATUS_EN);243		break;244 245	case SNDRV_PCM_TRIGGER_STOP:246	case SNDRV_PCM_TRIGGER_SUSPEND:247	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:248		mca_modify(cl, serdes_unit + REG_SERDES_STATUS,249			   SERDES_STATUS_EN, 0);250		break;251 252	default:253		return -EINVAL;254	}255 256	return 0;257}258 259static int mca_fe_enable_clocks(struct mca_cluster *cl)260{261	struct mca_data *mca = cl->host;262	int ret;263 264	ret = clk_prepare_enable(cl->clk_parent);265	if (ret) {266		dev_err(mca->dev,267			"cluster %d: unable to enable clock parent: %d\n",268			cl->no, ret);269		return ret;270	}271 272	/*273	 * We can't power up the device earlier than this because274	 * the power state driver would error out on seeing the device275	 * as clock-gated.276	 */277	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,278				      DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |279					      DL_FLAG_RPM_ACTIVE);280	if (!cl->pd_link) {281		dev_err(mca->dev,282			"cluster %d: unable to prop-up power domain\n", cl->no);283		clk_disable_unprepare(cl->clk_parent);284		return -EINVAL;285	}286 287	writel_relaxed(cl->no + 1, cl->base + REG_SYNCGEN_MCLK_SEL);288	mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN,289		   SYNCGEN_STATUS_EN);290	mca_modify(cl, REG_STATUS, STATUS_MCLK_EN, STATUS_MCLK_EN);291 292	return 0;293}294 295static void mca_fe_disable_clocks(struct mca_cluster *cl)296{297	mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);298	mca_modify(cl, REG_STATUS, STATUS_MCLK_EN, 0);299 300	device_link_del(cl->pd_link);301	clk_disable_unprepare(cl->clk_parent);302}303 304static bool mca_fe_clocks_in_use(struct mca_cluster *cl)305{306	struct mca_data *mca = cl->host;307	struct mca_cluster *be_cl;308	int stream, i;309 310	mutex_lock(&mca->port_mutex);311	for (i = 0; i < mca->nclusters; i++) {312		be_cl = &mca->clusters[i];313 314		if (be_cl->port_driver != cl->no)315			continue;316 317		for_each_pcm_streams(stream) {318			if (be_cl->clocks_in_use[stream]) {319				mutex_unlock(&mca->port_mutex);320				return true;321			}322		}323	}324	mutex_unlock(&mca->port_mutex);325	return false;326}327 328static int mca_be_prepare(struct snd_pcm_substream *substream,329			  struct snd_soc_dai *dai)330{331	struct mca_cluster *cl = mca_dai_to_cluster(dai);332	struct mca_data *mca = cl->host;333	struct mca_cluster *fe_cl;334	int ret;335 336	if (cl->port_driver < 0)337		return -EINVAL;338 339	fe_cl = &mca->clusters[cl->port_driver];340 341	/*342	 * Typically the CODECs we are paired with will require clocks343	 * to be present at time of unmute with the 'mute_stream' op344	 * or at time of DAPM widget power-up. We need to enable clocks345	 * here at the latest (frontend prepare would be too late).346	 */347	if (!mca_fe_clocks_in_use(fe_cl)) {348		ret = mca_fe_enable_clocks(fe_cl);349		if (ret < 0)350			return ret;351	}352 353	cl->clocks_in_use[substream->stream] = true;354 355	return 0;356}357 358static int mca_be_hw_free(struct snd_pcm_substream *substream,359			  struct snd_soc_dai *dai)360{361	struct mca_cluster *cl = mca_dai_to_cluster(dai);362	struct mca_data *mca = cl->host;363	struct mca_cluster *fe_cl;364 365	if (cl->port_driver < 0)366		return -EINVAL;367 368	/*369	 * We are operating on a foreign cluster here, but since we370	 * belong to the same PCM, accesses should have been371	 * synchronized at ASoC level.372	 */373	fe_cl = &mca->clusters[cl->port_driver];374	if (!mca_fe_clocks_in_use(fe_cl))375		return 0; /* Nothing to do */376 377	cl->clocks_in_use[substream->stream] = false;378 379	if (!mca_fe_clocks_in_use(fe_cl))380		mca_fe_disable_clocks(fe_cl);381 382	return 0;383}384 385static unsigned int mca_crop_mask(unsigned int mask, int nchans)386{387	while (hweight32(mask) > nchans)388		mask &= ~(1 << __fls(mask));389 390	return mask;391}392 393static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,394				unsigned int mask, int slots, int nchans,395				int slot_width, bool is_tx, int port)396{397	__iomem void *serdes_base = cl->base + serdes_unit;398	u32 serdes_conf, serdes_conf_mask;399 400	serdes_conf_mask = SERDES_CONF_WIDTH_MASK | SERDES_CONF_NCHANS;401	serdes_conf = FIELD_PREP(SERDES_CONF_NCHANS, max(slots, 1) - 1);402	switch (slot_width) {403	case 16:404		serdes_conf |= SERDES_CONF_WIDTH_16BIT;405		break;406	case 20:407		serdes_conf |= SERDES_CONF_WIDTH_20BIT;408		break;409	case 24:410		serdes_conf |= SERDES_CONF_WIDTH_24BIT;411		break;412	case 32:413		serdes_conf |= SERDES_CONF_WIDTH_32BIT;414		break;415	default:416		goto err;417	}418 419	serdes_conf_mask |= SERDES_CONF_SYNC_SEL;420	serdes_conf |= FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1);421 422	if (is_tx) {423		serdes_conf_mask |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 |424				    SERDES_CONF_UNK3;425		serdes_conf |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 |426			       SERDES_CONF_UNK3;427	} else {428		serdes_conf_mask |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 |429				    SERDES_CONF_UNK3 |430				    SERDES_CONF_NO_DATA_FEEDBACK;431		serdes_conf |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 |432			       SERDES_CONF_NO_DATA_FEEDBACK;433	}434 435	mca_modify(cl,436		   serdes_unit +437			   (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF),438		   serdes_conf_mask, serdes_conf);439 440	if (is_tx) {441		writel_relaxed(0xffffffff,442			       serdes_base + REG_TX_SERDES_SLOTMASK);443		writel_relaxed(~((u32)mca_crop_mask(mask, nchans)),444			       serdes_base + REG_TX_SERDES_SLOTMASK + 0x4);445		writel_relaxed(0xffffffff,446			       serdes_base + REG_TX_SERDES_SLOTMASK + 0x8);447		writel_relaxed(~((u32)mask),448			       serdes_base + REG_TX_SERDES_SLOTMASK + 0xc);449	} else {450		writel_relaxed(0xffffffff,451			       serdes_base + REG_RX_SERDES_SLOTMASK);452		writel_relaxed(~((u32)mca_crop_mask(mask, nchans)),453			       serdes_base + REG_RX_SERDES_SLOTMASK + 0x4);454		writel_relaxed(1 << port,455			       serdes_base + REG_RX_SERDES_PORT);456	}457 458	return 0;459 460err:461	dev_err(cl->host->dev,462		"unsupported SERDES configuration requested (mask=0x%x slots=%d slot_width=%d)\n",463		mask, slots, slot_width);464	return -EINVAL;465}466 467static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,468			       unsigned int rx_mask, int slots, int slot_width)469{470	struct mca_cluster *cl = mca_dai_to_cluster(dai);471 472	cl->tdm_slots = slots;473	cl->tdm_slot_width = slot_width;474	cl->tdm_tx_mask = tx_mask;475	cl->tdm_rx_mask = rx_mask;476 477	return 0;478}479 480static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)481{482	struct mca_cluster *cl = mca_dai_to_cluster(dai);483	struct mca_data *mca = cl->host;484	bool fpol_inv = false;485	u32 serdes_conf = 0;486	u32 bitstart;487 488	if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) !=489	    SND_SOC_DAIFMT_BP_FP)490		goto err;491 492	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {493	case SND_SOC_DAIFMT_I2S:494		fpol_inv = 0;495		bitstart = 1;496		break;497	case SND_SOC_DAIFMT_LEFT_J:498		fpol_inv = 1;499		bitstart = 0;500		break;501	default:502		goto err;503	}504 505	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {506	case SND_SOC_DAIFMT_NB_IF:507	case SND_SOC_DAIFMT_IB_IF:508		fpol_inv ^= 1;509		break;510	}511 512	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {513	case SND_SOC_DAIFMT_NB_NF:514	case SND_SOC_DAIFMT_NB_IF:515		serdes_conf |= SERDES_CONF_BCLK_POL;516		break;517	}518 519	if (!fpol_inv)520		goto err;521 522	mca_modify(cl, CLUSTER_TX_OFF + REG_TX_SERDES_CONF,523		   SERDES_CONF_BCLK_POL, serdes_conf);524	mca_modify(cl, CLUSTER_RX_OFF + REG_RX_SERDES_CONF,525		   SERDES_CONF_BCLK_POL, serdes_conf);526	writel_relaxed(bitstart,527		       cl->base + CLUSTER_TX_OFF + REG_TX_SERDES_BITSTART);528	writel_relaxed(bitstart,529		       cl->base + CLUSTER_RX_OFF + REG_RX_SERDES_BITSTART);530 531	return 0;532 533err:534	dev_err(mca->dev, "unsupported DAI format (0x%x) requested\n", fmt);535	return -EINVAL;536}537 538static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)539{540	struct mca_cluster *cl = mca_dai_to_cluster(dai);541 542	cl->bclk_ratio = ratio;543 544	return 0;545}546 547static int mca_fe_get_port(struct snd_pcm_substream *substream)548{549	struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);550	struct snd_soc_pcm_runtime *be;551	struct snd_soc_dpcm *dpcm;552 553	be = NULL;554	for_each_dpcm_be(fe, substream->stream, dpcm) {555		be = dpcm->be;556		break;557	}558 559	if (!be)560		return -EINVAL;561 562	return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;563}564 565static int mca_fe_hw_params(struct snd_pcm_substream *substream,566			    struct snd_pcm_hw_params *params,567			    struct snd_soc_dai *dai)568{569	struct mca_cluster *cl = mca_dai_to_cluster(dai);570	struct mca_data *mca = cl->host;571	struct device *dev = mca->dev;572	unsigned int samp_rate = params_rate(params);573	bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;574	bool refine_tdm = false;575	unsigned long bclk_ratio;576	unsigned int tdm_slots, tdm_slot_width, tdm_mask;577	u32 regval, pad;578	int ret, port, nchans_ceiled;579 580	if (!cl->tdm_slot_width) {581		/*582		 * We were not given TDM settings from above, set initial583		 * guesses which will later be refined.584		 */585		tdm_slot_width = params_width(params);586		tdm_slots = params_channels(params);587		refine_tdm = true;588	} else {589		tdm_slot_width = cl->tdm_slot_width;590		tdm_slots = cl->tdm_slots;591		tdm_mask = is_tx ? cl->tdm_tx_mask : cl->tdm_rx_mask;592	}593 594	if (cl->bclk_ratio)595		bclk_ratio = cl->bclk_ratio;596	else597		bclk_ratio = tdm_slot_width * tdm_slots;598 599	if (refine_tdm) {600		int nchannels = params_channels(params);601 602		if (nchannels > 2) {603			dev_err(dev, "missing TDM for stream with two or more channels\n");604			return -EINVAL;605		}606 607		if ((bclk_ratio % nchannels) != 0) {608			dev_err(dev, "BCLK ratio (%ld) not divisible by no. of channels (%d)\n",609				bclk_ratio, nchannels);610			return -EINVAL;611		}612 613		tdm_slot_width = bclk_ratio / nchannels;614 615		if (tdm_slot_width > 32 && nchannels == 1)616			tdm_slot_width = 32;617 618		if (tdm_slot_width < params_width(params)) {619			dev_err(dev, "TDM slots too narrow (tdm=%d params=%d)\n",620				tdm_slot_width, params_width(params));621			return -EINVAL;622		}623 624		tdm_mask = (1 << tdm_slots) - 1;625	}626 627	port = mca_fe_get_port(substream);628	if (port < 0)629		return port;630 631	ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF,632				   tdm_mask, tdm_slots, params_channels(params),633				   tdm_slot_width, is_tx, port);634	if (ret)635		return ret;636 637	pad = 32 - params_width(params);638 639	/*640	 * TODO: Here the register semantics aren't clear.641	 */642	nchans_ceiled = min_t(int, params_channels(params), 4);643	regval = FIELD_PREP(DMA_ADAPTER_NCHANS, nchans_ceiled) |644		 FIELD_PREP(DMA_ADAPTER_TX_NCHANS, 0x2) |645		 FIELD_PREP(DMA_ADAPTER_RX_NCHANS, 0x2) |646		 FIELD_PREP(DMA_ADAPTER_TX_LSB_PAD, pad) |647		 FIELD_PREP(DMA_ADAPTER_RX_MSB_PAD, pad);648 649#ifndef USE_RXB_FOR_CAPTURE650	writel_relaxed(regval, mca->switch_base + REG_DMA_ADAPTER_A(cl->no));651#else652	if (is_tx)653		writel_relaxed(regval,654			       mca->switch_base + REG_DMA_ADAPTER_A(cl->no));655	else656		writel_relaxed(regval,657			       mca->switch_base + REG_DMA_ADAPTER_B(cl->no));658#endif659 660	if (!mca_fe_clocks_in_use(cl)) {661		/*662		 * Set up FSYNC duty cycle as even as possible.663		 */664		writel_relaxed((bclk_ratio / 2) - 1,665			       cl->base + REG_SYNCGEN_HI_PERIOD);666		writel_relaxed(((bclk_ratio + 1) / 2) - 1,667			       cl->base + REG_SYNCGEN_LO_PERIOD);668		writel_relaxed(FIELD_PREP(MCLK_CONF_DIV, 0x1),669			       cl->base + REG_MCLK_CONF);670 671		ret = clk_set_rate(cl->clk_parent, bclk_ratio * samp_rate);672		if (ret) {673			dev_err(mca->dev, "cluster %d: unable to set clock parent: %d\n",674				cl->no, ret);675			return ret;676		}677	}678 679	return 0;680}681 682static const struct snd_soc_dai_ops mca_fe_ops = {683	.set_fmt = mca_fe_set_fmt,684	.set_bclk_ratio = mca_set_bclk_ratio,685	.set_tdm_slot = mca_fe_set_tdm_slot,686	.hw_params = mca_fe_hw_params,687	.trigger = mca_fe_trigger,688};689 690static bool mca_be_started(struct mca_cluster *cl)691{692	int stream;693 694	for_each_pcm_streams(stream)695		if (cl->port_started[stream])696			return true;697	return false;698}699 700static int mca_be_startup(struct snd_pcm_substream *substream,701			  struct snd_soc_dai *dai)702{703	struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);704	struct snd_soc_pcm_runtime *fe;705	struct mca_cluster *cl = mca_dai_to_cluster(dai);706	struct mca_cluster *fe_cl;707	struct mca_data *mca = cl->host;708	struct snd_soc_dpcm *dpcm;709 710	fe = NULL;711 712	for_each_dpcm_fe(be, substream->stream, dpcm) {713		if (fe && dpcm->fe != fe) {714			dev_err(mca->dev, "many FE per one BE unsupported\n");715			return -EINVAL;716		}717 718		fe = dpcm->fe;719	}720 721	if (!fe)722		return -EINVAL;723 724	fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));725 726	if (mca_be_started(cl)) {727		/*728		 * Port is already started in the other direction.729		 * Make sure there isn't a conflict with another cluster730		 * driving the port.731		 */732		if (cl->port_driver != fe_cl->no)733			return -EINVAL;734 735		cl->port_started[substream->stream] = true;736		return 0;737	}738 739	writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA,740		       cl->base + REG_PORT_ENABLES);741	writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1),742		       cl->base + REG_PORT_CLOCK_SEL);743	writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),744		       cl->base + REG_PORT_DATA_SEL);745	mutex_lock(&mca->port_mutex);746	cl->port_driver = fe_cl->no;747	mutex_unlock(&mca->port_mutex);748	cl->port_started[substream->stream] = true;749 750	return 0;751}752 753static void mca_be_shutdown(struct snd_pcm_substream *substream,754			    struct snd_soc_dai *dai)755{756	struct mca_cluster *cl = mca_dai_to_cluster(dai);757	struct mca_data *mca = cl->host;758 759	cl->port_started[substream->stream] = false;760 761	if (!mca_be_started(cl)) {762		/*763		 * Were we the last direction to shutdown?764		 * Turn off the lights.765		 */766		writel_relaxed(0, cl->base + REG_PORT_ENABLES);767		writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);768		mutex_lock(&mca->port_mutex);769		cl->port_driver = -1;770		mutex_unlock(&mca->port_mutex);771	}772}773 774static const struct snd_soc_dai_ops mca_be_ops = {775	.prepare = mca_be_prepare,776	.hw_free = mca_be_hw_free,777	.startup = mca_be_startup,778	.shutdown = mca_be_shutdown,779};780 781static int mca_set_runtime_hwparams(struct snd_soc_component *component,782				    struct snd_pcm_substream *substream,783				    struct dma_chan *chan)784{785	struct device *dma_dev = chan->device->dev;786	struct snd_dmaengine_dai_dma_data dma_data = {};787	int ret;788 789	struct snd_pcm_hardware hw;790 791	memset(&hw, 0, sizeof(hw));792 793	hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |794		  SNDRV_PCM_INFO_INTERLEAVED;795	hw.periods_min = 2;796	hw.periods_max = UINT_MAX;797	hw.period_bytes_min = 256;798	hw.period_bytes_max = dma_get_max_seg_size(dma_dev);799	hw.buffer_bytes_max = SIZE_MAX;800	hw.fifo_size = 16;801 802	ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, &dma_data,803							&hw, chan);804 805	if (ret)806		return ret;807 808	return snd_soc_set_runtime_hwparams(substream, &hw);809}810 811static int mca_pcm_open(struct snd_soc_component *component,812			struct snd_pcm_substream *substream)813{814	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);815	struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));816	struct dma_chan *chan = cl->dma_chans[substream->stream];817	int ret;818 819	if (rtd->dai_link->no_pcm)820		return 0;821 822	ret = mca_set_runtime_hwparams(component, substream, chan);823	if (ret)824		return ret;825 826	return snd_dmaengine_pcm_open(substream, chan);827}828 829static int mca_hw_params(struct snd_soc_component *component,830			 struct snd_pcm_substream *substream,831			 struct snd_pcm_hw_params *params)832{833	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);834	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);835	struct dma_slave_config slave_config;836	int ret;837 838	if (rtd->dai_link->no_pcm)839		return 0;840 841	memset(&slave_config, 0, sizeof(slave_config));842	ret = snd_hwparams_to_dma_slave_config(substream, params,843					       &slave_config);844	if (ret < 0)845		return ret;846 847	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)848		slave_config.dst_port_window_size =849			min_t(u32, params_channels(params), 4);850	else851		slave_config.src_port_window_size =852			min_t(u32, params_channels(params), 4);853 854	return dmaengine_slave_config(chan, &slave_config);855}856 857static int mca_close(struct snd_soc_component *component,858		     struct snd_pcm_substream *substream)859{860	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);861 862	if (rtd->dai_link->no_pcm)863		return 0;864 865	return snd_dmaengine_pcm_close(substream);866}867 868static int mca_trigger(struct snd_soc_component *component,869		       struct snd_pcm_substream *substream, int cmd)870{871	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);872 873	if (rtd->dai_link->no_pcm)874		return 0;875 876	/*877	 * Before we do the PCM trigger proper, insert an opportunity878	 * to reset the frontend's SERDES.879	 */880	mca_fe_early_trigger(substream, cmd, snd_soc_rtd_to_cpu(rtd, 0));881 882	return snd_dmaengine_pcm_trigger(substream, cmd);883}884 885static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component,886				     struct snd_pcm_substream *substream)887{888	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);889 890	if (rtd->dai_link->no_pcm)891		return -ENOTSUPP;892 893	return snd_dmaengine_pcm_pointer(substream);894}895 896static struct dma_chan *mca_request_dma_channel(struct mca_cluster *cl, unsigned int stream)897{898	bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);899#ifndef USE_RXB_FOR_CAPTURE900	char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL,901				    is_tx ? "tx%da" : "rx%da", cl->no);902#else903	char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL,904				    is_tx ? "tx%da" : "rx%db", cl->no);905#endif906	return of_dma_request_slave_channel(cl->host->dev->of_node, name);907 908}909 910static void mca_pcm_free(struct snd_soc_component *component,911			 struct snd_pcm *pcm)912{913	struct snd_soc_pcm_runtime *rtd = snd_pcm_chip(pcm);914	struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));915	unsigned int i;916 917	if (rtd->dai_link->no_pcm)918		return;919 920	for_each_pcm_streams(i) {921		struct snd_pcm_substream *substream =922			rtd->pcm->streams[i].substream;923 924		if (!substream || !cl->dma_chans[i])925			continue;926 927		dma_release_channel(cl->dma_chans[i]);928		cl->dma_chans[i] = NULL;929	}930}931 932 933static int mca_pcm_new(struct snd_soc_component *component,934		       struct snd_soc_pcm_runtime *rtd)935{936	struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));937	unsigned int i;938 939	if (rtd->dai_link->no_pcm)940		return 0;941 942	for_each_pcm_streams(i) {943		struct snd_pcm_substream *substream =944			rtd->pcm->streams[i].substream;945		struct dma_chan *chan;946 947		if (!substream)948			continue;949 950		chan = mca_request_dma_channel(cl, i);951 952		if (IS_ERR_OR_NULL(chan)) {953			mca_pcm_free(component, rtd->pcm);954 955			if (chan && PTR_ERR(chan) == -EPROBE_DEFER)956				return PTR_ERR(chan);957 958			dev_err(component->dev, "unable to obtain DMA channel (stream %d cluster %d): %pe\n",959				i, cl->no, chan);960 961			if (!chan)962				return -EINVAL;963			return PTR_ERR(chan);964		}965 966		cl->dma_chans[i] = chan;967		snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_IRAM,968					   chan->device->dev, 512 * 1024 * 6,969					   SIZE_MAX);970	}971 972	return 0;973}974 975static const struct snd_soc_component_driver mca_component = {976	.name = "apple-mca",977	.open = mca_pcm_open,978	.close = mca_close,979	.hw_params = mca_hw_params,980	.trigger = mca_trigger,981	.pointer = mca_pointer,982	.pcm_construct = mca_pcm_new,983	.pcm_destruct = mca_pcm_free,984};985 986static void apple_mca_release(struct mca_data *mca)987{988	int i;989 990	for (i = 0; i < mca->nclusters; i++) {991		struct mca_cluster *cl = &mca->clusters[i];992 993		if (!IS_ERR_OR_NULL(cl->clk_parent))994			clk_put(cl->clk_parent);995 996		if (!IS_ERR_OR_NULL(cl->pd_dev))997			dev_pm_domain_detach(cl->pd_dev, true);998	}999 1000	if (mca->pd_link)1001		device_link_del(mca->pd_link);1002 1003	if (!IS_ERR_OR_NULL(mca->pd_dev))1004		dev_pm_domain_detach(mca->pd_dev, true);1005 1006	reset_control_rearm(mca->rstc);1007}1008 1009static int apple_mca_probe(struct platform_device *pdev)1010{1011	struct mca_data *mca;1012	struct mca_cluster *clusters;1013	struct snd_soc_dai_driver *dai_drivers;1014	struct resource *res;1015	void __iomem *base;1016	int nclusters;1017	int ret, i;1018 1019	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);1020	if (IS_ERR(base))1021		return PTR_ERR(base);1022 1023	if (resource_size(res) < CLUSTER_STRIDE)1024		return -EINVAL;1025	nclusters = (resource_size(res) - CLUSTER_STRIDE) / CLUSTER_STRIDE + 1;1026 1027	mca = devm_kzalloc(&pdev->dev, struct_size(mca, clusters, nclusters),1028			   GFP_KERNEL);1029	if (!mca)1030		return -ENOMEM;1031	mca->dev = &pdev->dev;1032	mca->nclusters = nclusters;1033	mutex_init(&mca->port_mutex);1034	platform_set_drvdata(pdev, mca);1035	clusters = mca->clusters;1036 1037	mca->switch_base =1038		devm_platform_ioremap_resource(pdev, 1);1039	if (IS_ERR(mca->switch_base))1040		return PTR_ERR(mca->switch_base);1041 1042	mca->rstc = devm_reset_control_get_optional_shared(&pdev->dev, NULL);1043	if (IS_ERR(mca->rstc))1044		return PTR_ERR(mca->rstc);1045 1046	dai_drivers = devm_kzalloc(1047		&pdev->dev, sizeof(*dai_drivers) * 2 * nclusters, GFP_KERNEL);1048	if (!dai_drivers)1049		return -ENOMEM;1050 1051	mca->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, 0);1052	if (IS_ERR(mca->pd_dev))1053		return -EINVAL;1054 1055	mca->pd_link = device_link_add(&pdev->dev, mca->pd_dev,1056				       DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |1057					       DL_FLAG_RPM_ACTIVE);1058	if (!mca->pd_link) {1059		ret = -EINVAL;1060		/* Prevent an unbalanced reset rearm */1061		mca->rstc = NULL;1062		goto err_release;1063	}1064 1065	reset_control_reset(mca->rstc);1066 1067	for (i = 0; i < nclusters; i++) {1068		struct mca_cluster *cl = &clusters[i];1069		struct snd_soc_dai_driver *fe =1070			&dai_drivers[mca->nclusters + i];1071		struct snd_soc_dai_driver *be = &dai_drivers[i];1072 1073		cl->host = mca;1074		cl->no = i;1075		cl->base = base + CLUSTER_STRIDE * i;1076		cl->port_driver = -1;1077		cl->clk_parent = of_clk_get(pdev->dev.of_node, i);1078		if (IS_ERR(cl->clk_parent)) {1079			dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n",1080				i, PTR_ERR(cl->clk_parent));1081			ret = PTR_ERR(cl->clk_parent);1082			goto err_release;1083		}1084		cl->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i + 1);1085		if (IS_ERR(cl->pd_dev)) {1086			dev_err(&pdev->dev,1087				"unable to obtain cluster %d PD: %ld\n", i,1088				PTR_ERR(cl->pd_dev));1089			ret = PTR_ERR(cl->pd_dev);1090			goto err_release;1091		}1092 1093		fe->id = i;1094		fe->name =1095			devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-pcm-%d", i);1096		if (!fe->name) {1097			ret = -ENOMEM;1098			goto err_release;1099		}1100		fe->ops = &mca_fe_ops;1101		fe->playback.channels_min = 1;1102		fe->playback.channels_max = 32;1103		fe->playback.rates = SNDRV_PCM_RATE_8000_192000;1104		fe->playback.formats = APPLE_MCA_FMTBITS;1105		fe->capture.channels_min = 1;1106		fe->capture.channels_max = 32;1107		fe->capture.rates = SNDRV_PCM_RATE_8000_192000;1108		fe->capture.formats = APPLE_MCA_FMTBITS;1109		fe->symmetric_rate = 1;1110 1111		fe->playback.stream_name =1112			devm_kasprintf(&pdev->dev, GFP_KERNEL, "PCM%d TX", i);1113		fe->capture.stream_name =1114			devm_kasprintf(&pdev->dev, GFP_KERNEL, "PCM%d RX", i);1115 1116		if (!fe->playback.stream_name || !fe->capture.stream_name) {1117			ret = -ENOMEM;1118			goto err_release;1119		}1120 1121		be->id = i + nclusters;1122		be->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-i2s-%d", i);1123		if (!be->name) {1124			ret = -ENOMEM;1125			goto err_release;1126		}1127		be->ops = &mca_be_ops;1128		be->playback.channels_min = 1;1129		be->playback.channels_max = 32;1130		be->playback.rates = SNDRV_PCM_RATE_8000_192000;1131		be->playback.formats = APPLE_MCA_FMTBITS;1132		be->capture.channels_min = 1;1133		be->capture.channels_max = 32;1134		be->capture.rates = SNDRV_PCM_RATE_8000_192000;1135		be->capture.formats = APPLE_MCA_FMTBITS;1136 1137		be->playback.stream_name =1138			devm_kasprintf(&pdev->dev, GFP_KERNEL, "I2S%d TX", i);1139		be->capture.stream_name =1140			devm_kasprintf(&pdev->dev, GFP_KERNEL, "I2S%d RX", i);1141		if (!be->playback.stream_name || !be->capture.stream_name) {1142			ret = -ENOMEM;1143			goto err_release;1144		}1145	}1146 1147	ret = snd_soc_register_component(&pdev->dev, &mca_component,1148					 dai_drivers, nclusters * 2);1149	if (ret) {1150		dev_err(&pdev->dev, "unable to register ASoC component: %d\n",1151			ret);1152		goto err_release;1153	}1154 1155	return 0;1156 1157err_release:1158	apple_mca_release(mca);1159	return ret;1160}1161 1162static void apple_mca_remove(struct platform_device *pdev)1163{1164	struct mca_data *mca = platform_get_drvdata(pdev);1165 1166	snd_soc_unregister_component(&pdev->dev);1167	apple_mca_release(mca);1168}1169 1170static const struct of_device_id apple_mca_of_match[] = {1171	{ .compatible = "apple,mca", },1172	{}1173};1174MODULE_DEVICE_TABLE(of, apple_mca_of_match);1175 1176static struct platform_driver apple_mca_driver = {1177	.driver = {1178		.name = "apple-mca",1179		.of_match_table = apple_mca_of_match,1180	},1181	.probe = apple_mca_probe,1182	.remove = apple_mca_remove,1183};1184module_platform_driver(apple_mca_driver);1185 1186MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");1187MODULE_DESCRIPTION("ASoC Apple MCA driver");1188MODULE_LICENSE("GPL");1189