162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ALSA SoC McASP Audio Layer for TI DAVINCI processor
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Multi-channel Audio Serial Port Driver
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Nirmal Pandey <n-pandey@ti.com>,
862306a36Sopenharmony_ci *         Suresh Rajashekara <suresh.r@ti.com>
962306a36Sopenharmony_ci *         Steve Chen <schen@.mvista.com>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
1262306a36Sopenharmony_ci * Copyright:   (C) 2009  Texas Instruments, India
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/device.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci#include <linux/io.h>
2162306a36Sopenharmony_ci#include <linux/clk.h>
2262306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/of_platform.h>
2562306a36Sopenharmony_ci#include <linux/of_device.h>
2662306a36Sopenharmony_ci#include <linux/platform_data/davinci_asp.h>
2762306a36Sopenharmony_ci#include <linux/math64.h>
2862306a36Sopenharmony_ci#include <linux/bitmap.h>
2962306a36Sopenharmony_ci#include <linux/gpio/driver.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <sound/asoundef.h>
3262306a36Sopenharmony_ci#include <sound/core.h>
3362306a36Sopenharmony_ci#include <sound/pcm.h>
3462306a36Sopenharmony_ci#include <sound/pcm_params.h>
3562306a36Sopenharmony_ci#include <sound/initval.h>
3662306a36Sopenharmony_ci#include <sound/soc.h>
3762306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include "edma-pcm.h"
4062306a36Sopenharmony_ci#include "sdma-pcm.h"
4162306a36Sopenharmony_ci#include "udma-pcm.h"
4262306a36Sopenharmony_ci#include "davinci-mcasp.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define MCASP_MAX_AFIFO_DEPTH	64
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#ifdef CONFIG_PM
4762306a36Sopenharmony_cistatic u32 context_regs[] = {
4862306a36Sopenharmony_ci	DAVINCI_MCASP_TXFMCTL_REG,
4962306a36Sopenharmony_ci	DAVINCI_MCASP_RXFMCTL_REG,
5062306a36Sopenharmony_ci	DAVINCI_MCASP_TXFMT_REG,
5162306a36Sopenharmony_ci	DAVINCI_MCASP_RXFMT_REG,
5262306a36Sopenharmony_ci	DAVINCI_MCASP_ACLKXCTL_REG,
5362306a36Sopenharmony_ci	DAVINCI_MCASP_ACLKRCTL_REG,
5462306a36Sopenharmony_ci	DAVINCI_MCASP_AHCLKXCTL_REG,
5562306a36Sopenharmony_ci	DAVINCI_MCASP_AHCLKRCTL_REG,
5662306a36Sopenharmony_ci	DAVINCI_MCASP_PDIR_REG,
5762306a36Sopenharmony_ci	DAVINCI_MCASP_PFUNC_REG,
5862306a36Sopenharmony_ci	DAVINCI_MCASP_RXMASK_REG,
5962306a36Sopenharmony_ci	DAVINCI_MCASP_TXMASK_REG,
6062306a36Sopenharmony_ci	DAVINCI_MCASP_RXTDM_REG,
6162306a36Sopenharmony_ci	DAVINCI_MCASP_TXTDM_REG,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct davinci_mcasp_context {
6562306a36Sopenharmony_ci	u32	config_regs[ARRAY_SIZE(context_regs)];
6662306a36Sopenharmony_ci	u32	afifo_regs[2]; /* for read/write fifo control registers */
6762306a36Sopenharmony_ci	u32	*xrsr_regs; /* for serializer configuration */
6862306a36Sopenharmony_ci	bool	pm_state;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct davinci_mcasp_ruledata {
7362306a36Sopenharmony_ci	struct davinci_mcasp *mcasp;
7462306a36Sopenharmony_ci	int serializers;
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct davinci_mcasp {
7862306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data dma_data[2];
7962306a36Sopenharmony_ci	struct davinci_mcasp_pdata *pdata;
8062306a36Sopenharmony_ci	void __iomem *base;
8162306a36Sopenharmony_ci	u32 fifo_base;
8262306a36Sopenharmony_ci	struct device *dev;
8362306a36Sopenharmony_ci	struct snd_pcm_substream *substreams[2];
8462306a36Sopenharmony_ci	unsigned int dai_fmt;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	u32 iec958_status;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* Audio can not be enabled due to missing parameter(s) */
8962306a36Sopenharmony_ci	bool	missing_audio_param;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* McASP specific data */
9262306a36Sopenharmony_ci	int	tdm_slots;
9362306a36Sopenharmony_ci	u32	tdm_mask[2];
9462306a36Sopenharmony_ci	int	slot_width;
9562306a36Sopenharmony_ci	u8	op_mode;
9662306a36Sopenharmony_ci	u8	dismod;
9762306a36Sopenharmony_ci	u8	num_serializer;
9862306a36Sopenharmony_ci	u8	*serial_dir;
9962306a36Sopenharmony_ci	u8	version;
10062306a36Sopenharmony_ci	u8	bclk_div;
10162306a36Sopenharmony_ci	int	streams;
10262306a36Sopenharmony_ci	u32	irq_request[2];
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	int	sysclk_freq;
10562306a36Sopenharmony_ci	bool	bclk_master;
10662306a36Sopenharmony_ci	u32	auxclk_fs_ratio;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	unsigned long pdir; /* Pin direction bitfield */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* McASP FIFO related */
11162306a36Sopenharmony_ci	u8	txnumevt;
11262306a36Sopenharmony_ci	u8	rxnumevt;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	bool	dat_port;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Used for comstraint setting on the second stream */
11762306a36Sopenharmony_ci	u32	channels;
11862306a36Sopenharmony_ci	int	max_format_width;
11962306a36Sopenharmony_ci	u8	active_serializers[2];
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB
12262306a36Sopenharmony_ci	struct gpio_chip gpio_chip;
12362306a36Sopenharmony_ci#endif
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#ifdef CONFIG_PM
12662306a36Sopenharmony_ci	struct davinci_mcasp_context context;
12762306a36Sopenharmony_ci#endif
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	struct davinci_mcasp_ruledata ruledata[2];
13062306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_list chconstr[2];
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
13462306a36Sopenharmony_ci				  u32 val)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
13762306a36Sopenharmony_ci	__raw_writel(__raw_readl(reg) | val, reg);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
14162306a36Sopenharmony_ci				  u32 val)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
14462306a36Sopenharmony_ci	__raw_writel((__raw_readl(reg) & ~(val)), reg);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
14862306a36Sopenharmony_ci				  u32 val, u32 mask)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
15162306a36Sopenharmony_ci	__raw_writel((__raw_readl(reg) & ~mask) | val, reg);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
15562306a36Sopenharmony_ci				 u32 val)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	__raw_writel(val, mcasp->base + offset);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return (u32)__raw_readl(mcasp->base + offset);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	int i = 0;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	mcasp_set_bits(mcasp, ctl_reg, val);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* programming GBLCTL needs to read back from GBLCTL and verfiy */
17262306a36Sopenharmony_ci	/* loop count is to avoid the lock-up */
17362306a36Sopenharmony_ci	for (i = 0; i < 1000; i++) {
17462306a36Sopenharmony_ci		if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
17962306a36Sopenharmony_ci		printk(KERN_ERR "GBLCTL write error\n");
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
18562306a36Sopenharmony_ci	u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	u32 bit = PIN_BIT_AMUTE;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
19562306a36Sopenharmony_ci		if (enable)
19662306a36Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
19762306a36Sopenharmony_ci		else
19862306a36Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	u32 bit;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) {
20762306a36Sopenharmony_ci		if (enable)
20862306a36Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
20962306a36Sopenharmony_ci		else
21062306a36Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void mcasp_start_rx(struct davinci_mcasp *mcasp)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	if (mcasp->rxnumevt) {	/* enable FIFO */
21762306a36Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
22062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Start clocks */
22462306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
22562306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * When ASYNC == 0 the transmit and receive sections operate
22862306a36Sopenharmony_ci	 * synchronously from the transmit clock and frame sync. We need to make
22962306a36Sopenharmony_ci	 * sure that the TX signlas are enabled when starting reception.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci	if (mcasp_is_synchronous(mcasp)) {
23262306a36Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
23362306a36Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
23462306a36Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, true);
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Activate serializer(s) */
23862306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
23962306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
24062306a36Sopenharmony_ci	/* Release RX state machine */
24162306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
24262306a36Sopenharmony_ci	/* Release Frame Sync generator */
24362306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
24462306a36Sopenharmony_ci	if (mcasp_is_synchronous(mcasp))
24562306a36Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* enable receive IRQs */
24862306a36Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
24962306a36Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void mcasp_start_tx(struct davinci_mcasp *mcasp)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	u32 cnt;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (mcasp->txnumevt) {	/* enable FIFO */
25762306a36Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
26062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Start clocks */
26462306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
26562306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
26662306a36Sopenharmony_ci	mcasp_set_clk_pdir(mcasp, true);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Activate serializer(s) */
26962306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
27062306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* wait for XDATA to be cleared */
27362306a36Sopenharmony_ci	cnt = 0;
27462306a36Sopenharmony_ci	while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
27562306a36Sopenharmony_ci	       (cnt < 100000))
27662306a36Sopenharmony_ci		cnt++;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	mcasp_set_axr_pdir(mcasp, true);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Release TX state machine */
28162306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
28262306a36Sopenharmony_ci	/* Release Frame Sync generator */
28362306a36Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* enable transmit IRQs */
28662306a36Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
28762306a36Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	mcasp->streams++;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
29562306a36Sopenharmony_ci		mcasp_start_tx(mcasp);
29662306a36Sopenharmony_ci	else
29762306a36Sopenharmony_ci		mcasp_start_rx(mcasp);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void mcasp_stop_rx(struct davinci_mcasp *mcasp)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	/* disable IRQ sources */
30362306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
30462306a36Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/*
30762306a36Sopenharmony_ci	 * In synchronous mode stop the TX clocks if no other stream is
30862306a36Sopenharmony_ci	 * running
30962306a36Sopenharmony_ci	 */
31062306a36Sopenharmony_ci	if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
31162306a36Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, false);
31262306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
31662306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (mcasp->rxnumevt) {	/* disable FIFO */
31962306a36Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void mcasp_stop_tx(struct davinci_mcasp *mcasp)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	u32 val = 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* disable IRQ sources */
33062306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
33162306a36Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/*
33462306a36Sopenharmony_ci	 * In synchronous mode keep TX clocks running if the capture stream is
33562306a36Sopenharmony_ci	 * still running.
33662306a36Sopenharmony_ci	 */
33762306a36Sopenharmony_ci	if (mcasp_is_synchronous(mcasp) && mcasp->streams)
33862306a36Sopenharmony_ci		val =  TXHCLKRST | TXCLKRST | TXFSRST;
33962306a36Sopenharmony_ci	else
34062306a36Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, false);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
34462306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (mcasp->txnumevt) {	/* disable FIFO */
34762306a36Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	mcasp_set_axr_pdir(mcasp, false);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	mcasp->streams--;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
36062306a36Sopenharmony_ci		mcasp_stop_tx(mcasp);
36162306a36Sopenharmony_ci	else
36262306a36Sopenharmony_ci		mcasp_stop_rx(mcasp);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
36862306a36Sopenharmony_ci	struct snd_pcm_substream *substream;
36962306a36Sopenharmony_ci	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
37062306a36Sopenharmony_ci	u32 handled_mask = 0;
37162306a36Sopenharmony_ci	u32 stat;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
37462306a36Sopenharmony_ci	if (stat & XUNDRN & irq_mask) {
37562306a36Sopenharmony_ci		dev_warn(mcasp->dev, "Transmit buffer underflow\n");
37662306a36Sopenharmony_ci		handled_mask |= XUNDRN;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
37962306a36Sopenharmony_ci		if (substream)
38062306a36Sopenharmony_ci			snd_pcm_stop_xrun(substream);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!handled_mask)
38462306a36Sopenharmony_ci		dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
38562306a36Sopenharmony_ci			 stat);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (stat & XRERR)
38862306a36Sopenharmony_ci		handled_mask |= XRERR;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* Ack the handled event only */
39162306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return IRQ_RETVAL(handled_mask);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
39962306a36Sopenharmony_ci	struct snd_pcm_substream *substream;
40062306a36Sopenharmony_ci	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
40162306a36Sopenharmony_ci	u32 handled_mask = 0;
40262306a36Sopenharmony_ci	u32 stat;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
40562306a36Sopenharmony_ci	if (stat & ROVRN & irq_mask) {
40662306a36Sopenharmony_ci		dev_warn(mcasp->dev, "Receive buffer overflow\n");
40762306a36Sopenharmony_ci		handled_mask |= ROVRN;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
41062306a36Sopenharmony_ci		if (substream)
41162306a36Sopenharmony_ci			snd_pcm_stop_xrun(substream);
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (!handled_mask)
41562306a36Sopenharmony_ci		dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
41662306a36Sopenharmony_ci			 stat);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (stat & XRERR)
41962306a36Sopenharmony_ci		handled_mask |= XRERR;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Ack the handled event only */
42262306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return IRQ_RETVAL(handled_mask);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
43062306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
43362306a36Sopenharmony_ci		ret = davinci_mcasp_tx_irq_handler(irq, data);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
43662306a36Sopenharmony_ci		ret |= davinci_mcasp_rx_irq_handler(irq, data);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return ret;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
44262306a36Sopenharmony_ci					 unsigned int fmt)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
44562306a36Sopenharmony_ci	int ret = 0;
44662306a36Sopenharmony_ci	u32 data_delay;
44762306a36Sopenharmony_ci	bool fs_pol_rising;
44862306a36Sopenharmony_ci	bool inv_fs = false;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (!fmt)
45162306a36Sopenharmony_ci		return 0;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
45462306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
45562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
45662306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
45762306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
45862306a36Sopenharmony_ci		/* 1st data bit occur one ACLK cycle after the frame sync */
45962306a36Sopenharmony_ci		data_delay = 1;
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B:
46262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_AC97:
46362306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
46462306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
46562306a36Sopenharmony_ci		/* No delay after FS */
46662306a36Sopenharmony_ci		data_delay = 0;
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
46962306a36Sopenharmony_ci		/* configure a full-word SYNC pulse (LRCLK) */
47062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
47162306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
47262306a36Sopenharmony_ci		/* 1st data bit occur one ACLK cycle after the frame sync */
47362306a36Sopenharmony_ci		data_delay = 1;
47462306a36Sopenharmony_ci		/* FS need to be inverted */
47562306a36Sopenharmony_ci		inv_fs = true;
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
47862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
47962306a36Sopenharmony_ci		/* configure a full-word SYNC pulse (LRCLK) */
48062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
48162306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
48262306a36Sopenharmony_ci		/* No delay after FS */
48362306a36Sopenharmony_ci		data_delay = 0;
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	default:
48662306a36Sopenharmony_ci		ret = -EINVAL;
48762306a36Sopenharmony_ci		goto out;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
49162306a36Sopenharmony_ci		       FSXDLY(3));
49262306a36Sopenharmony_ci	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
49362306a36Sopenharmony_ci		       FSRDLY(3));
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
49662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BP_FP:
49762306a36Sopenharmony_ci		/* codec is clock and frame slave */
49862306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
49962306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
50262306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		/* BCLK */
50562306a36Sopenharmony_ci		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
50662306a36Sopenharmony_ci		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
50762306a36Sopenharmony_ci		/* Frame Sync */
50862306a36Sopenharmony_ci		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
50962306a36Sopenharmony_ci		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		mcasp->bclk_master = 1;
51262306a36Sopenharmony_ci		break;
51362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BP_FC:
51462306a36Sopenharmony_ci		/* codec is clock slave and frame master */
51562306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
51662306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
51962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		/* BCLK */
52262306a36Sopenharmony_ci		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
52362306a36Sopenharmony_ci		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
52462306a36Sopenharmony_ci		/* Frame Sync */
52562306a36Sopenharmony_ci		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
52662306a36Sopenharmony_ci		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		mcasp->bclk_master = 1;
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BC_FP:
53162306a36Sopenharmony_ci		/* codec is clock master and frame slave */
53262306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
53362306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
53662306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		/* BCLK */
53962306a36Sopenharmony_ci		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
54062306a36Sopenharmony_ci		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
54162306a36Sopenharmony_ci		/* Frame Sync */
54262306a36Sopenharmony_ci		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
54362306a36Sopenharmony_ci		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		mcasp->bclk_master = 0;
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BC_FC:
54862306a36Sopenharmony_ci		/* codec is clock and frame master */
54962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
55062306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
55362306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		/* BCLK */
55662306a36Sopenharmony_ci		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
55762306a36Sopenharmony_ci		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
55862306a36Sopenharmony_ci		/* Frame Sync */
55962306a36Sopenharmony_ci		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
56062306a36Sopenharmony_ci		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		mcasp->bclk_master = 0;
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci	default:
56562306a36Sopenharmony_ci		ret = -EINVAL;
56662306a36Sopenharmony_ci		goto out;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
57062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF:
57162306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
57262306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
57362306a36Sopenharmony_ci		fs_pol_rising = true;
57462306a36Sopenharmony_ci		break;
57562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_IF:
57662306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
57762306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
57862306a36Sopenharmony_ci		fs_pol_rising = false;
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_IF:
58162306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
58262306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
58362306a36Sopenharmony_ci		fs_pol_rising = false;
58462306a36Sopenharmony_ci		break;
58562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
58662306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
58762306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
58862306a36Sopenharmony_ci		fs_pol_rising = true;
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci	default:
59162306a36Sopenharmony_ci		ret = -EINVAL;
59262306a36Sopenharmony_ci		goto out;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (inv_fs)
59662306a36Sopenharmony_ci		fs_pol_rising = !fs_pol_rising;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (fs_pol_rising) {
59962306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
60062306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
60162306a36Sopenharmony_ci	} else {
60262306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
60362306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	mcasp->dai_fmt = fmt;
60762306a36Sopenharmony_ciout:
60862306a36Sopenharmony_ci	pm_runtime_put(mcasp->dev);
60962306a36Sopenharmony_ci	return ret;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
61362306a36Sopenharmony_ci				      int div, bool explicit)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
61662306a36Sopenharmony_ci	switch (div_id) {
61762306a36Sopenharmony_ci	case MCASP_CLKDIV_AUXCLK:			/* MCLK divider */
61862306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
61962306a36Sopenharmony_ci			       AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
62062306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
62162306a36Sopenharmony_ci			       AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
62262306a36Sopenharmony_ci		break;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	case MCASP_CLKDIV_BCLK:			/* BCLK divider */
62562306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
62662306a36Sopenharmony_ci			       ACLKXDIV(div - 1), ACLKXDIV_MASK);
62762306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
62862306a36Sopenharmony_ci			       ACLKRDIV(div - 1), ACLKRDIV_MASK);
62962306a36Sopenharmony_ci		if (explicit)
63062306a36Sopenharmony_ci			mcasp->bclk_div = div;
63162306a36Sopenharmony_ci		break;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	case MCASP_CLKDIV_BCLK_FS_RATIO:
63462306a36Sopenharmony_ci		/*
63562306a36Sopenharmony_ci		 * BCLK/LRCLK ratio descries how many bit-clock cycles
63662306a36Sopenharmony_ci		 * fit into one frame. The clock ratio is given for a
63762306a36Sopenharmony_ci		 * full period of data (for I2S format both left and
63862306a36Sopenharmony_ci		 * right channels), so it has to be divided by number
63962306a36Sopenharmony_ci		 * of tdm-slots (for I2S - divided by 2).
64062306a36Sopenharmony_ci		 * Instead of storing this ratio, we calculate a new
64162306a36Sopenharmony_ci		 * tdm_slot width by dividing the ratio by the
64262306a36Sopenharmony_ci		 * number of configured tdm slots.
64362306a36Sopenharmony_ci		 */
64462306a36Sopenharmony_ci		mcasp->slot_width = div / mcasp->tdm_slots;
64562306a36Sopenharmony_ci		if (div % mcasp->tdm_slots)
64662306a36Sopenharmony_ci			dev_warn(mcasp->dev,
64762306a36Sopenharmony_ci				 "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
64862306a36Sopenharmony_ci				 __func__, div, mcasp->tdm_slots);
64962306a36Sopenharmony_ci		break;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	default:
65262306a36Sopenharmony_ci		return -EINVAL;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	pm_runtime_put(mcasp->dev);
65662306a36Sopenharmony_ci	return 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
66062306a36Sopenharmony_ci				    int div)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
66862306a36Sopenharmony_ci				    unsigned int freq, int dir)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (dir == SND_SOC_CLOCK_IN) {
67562306a36Sopenharmony_ci		switch (clk_id) {
67662306a36Sopenharmony_ci		case MCASP_CLK_HCLK_AHCLK:
67762306a36Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
67862306a36Sopenharmony_ci				       AHCLKXE);
67962306a36Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
68062306a36Sopenharmony_ci				       AHCLKRE);
68162306a36Sopenharmony_ci			clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
68262306a36Sopenharmony_ci			break;
68362306a36Sopenharmony_ci		case MCASP_CLK_HCLK_AUXCLK:
68462306a36Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
68562306a36Sopenharmony_ci				       AHCLKXE);
68662306a36Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
68762306a36Sopenharmony_ci				       AHCLKRE);
68862306a36Sopenharmony_ci			set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
68962306a36Sopenharmony_ci			break;
69062306a36Sopenharmony_ci		default:
69162306a36Sopenharmony_ci			dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id);
69262306a36Sopenharmony_ci			goto out;
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci	} else {
69562306a36Sopenharmony_ci		/* Select AUXCLK as HCLK */
69662306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
69762306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
69862306a36Sopenharmony_ci		set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci	/*
70162306a36Sopenharmony_ci	 * When AHCLK X/R is selected to be output it means that the HCLK is
70262306a36Sopenharmony_ci	 * the same clock - coming via AUXCLK.
70362306a36Sopenharmony_ci	 */
70462306a36Sopenharmony_ci	mcasp->sysclk_freq = freq;
70562306a36Sopenharmony_ciout:
70662306a36Sopenharmony_ci	pm_runtime_put(mcasp->dev);
70762306a36Sopenharmony_ci	return 0;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci/* All serializers must have equal number of channels */
71162306a36Sopenharmony_cistatic int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
71262306a36Sopenharmony_ci				       int serializers)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
71562306a36Sopenharmony_ci	unsigned int *list = (unsigned int *) cl->list;
71662306a36Sopenharmony_ci	int slots = mcasp->tdm_slots;
71762306a36Sopenharmony_ci	int i, count = 0;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (mcasp->tdm_mask[stream])
72062306a36Sopenharmony_ci		slots = hweight32(mcasp->tdm_mask[stream]);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	for (i = 1; i <= slots; i++)
72362306a36Sopenharmony_ci		list[count++] = i;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	for (i = 2; i <= serializers; i++)
72662306a36Sopenharmony_ci		list[count++] = i*slots;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	cl->count = count;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	int rx_serializers = 0, tx_serializers = 0, ret, i;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
73862306a36Sopenharmony_ci		if (mcasp->serial_dir[i] == TX_MODE)
73962306a36Sopenharmony_ci			tx_serializers++;
74062306a36Sopenharmony_ci		else if (mcasp->serial_dir[i] == RX_MODE)
74162306a36Sopenharmony_ci			rx_serializers++;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
74462306a36Sopenharmony_ci					  tx_serializers);
74562306a36Sopenharmony_ci	if (ret)
74662306a36Sopenharmony_ci		return ret;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
74962306a36Sopenharmony_ci					  rx_serializers);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return ret;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
75662306a36Sopenharmony_ci				      unsigned int tx_mask,
75762306a36Sopenharmony_ci				      unsigned int rx_mask,
75862306a36Sopenharmony_ci				      int slots, int slot_width)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	dev_dbg(mcasp->dev,
76662306a36Sopenharmony_ci		 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
76762306a36Sopenharmony_ci		 __func__, tx_mask, rx_mask, slots, slot_width);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
77062306a36Sopenharmony_ci		dev_err(mcasp->dev,
77162306a36Sopenharmony_ci			"Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
77262306a36Sopenharmony_ci			tx_mask, rx_mask, slots);
77362306a36Sopenharmony_ci		return -EINVAL;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (slot_width &&
77762306a36Sopenharmony_ci	    (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
77862306a36Sopenharmony_ci		dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
77962306a36Sopenharmony_ci			__func__, slot_width);
78062306a36Sopenharmony_ci		return -EINVAL;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	mcasp->tdm_slots = slots;
78462306a36Sopenharmony_ci	mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
78562306a36Sopenharmony_ci	mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
78662306a36Sopenharmony_ci	mcasp->slot_width = slot_width;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return davinci_mcasp_set_ch_constraints(mcasp);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic int davinci_config_channel_size(struct davinci_mcasp *mcasp,
79262306a36Sopenharmony_ci				       int sample_width)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	u32 fmt;
79562306a36Sopenharmony_ci	u32 tx_rotate, rx_rotate, slot_width;
79662306a36Sopenharmony_ci	u32 mask = (1ULL << sample_width) - 1;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (mcasp->slot_width)
79962306a36Sopenharmony_ci		slot_width = mcasp->slot_width;
80062306a36Sopenharmony_ci	else if (mcasp->max_format_width)
80162306a36Sopenharmony_ci		slot_width = mcasp->max_format_width;
80262306a36Sopenharmony_ci	else
80362306a36Sopenharmony_ci		slot_width = sample_width;
80462306a36Sopenharmony_ci	/*
80562306a36Sopenharmony_ci	 * TX rotation:
80662306a36Sopenharmony_ci	 * right aligned formats: rotate w/ slot_width
80762306a36Sopenharmony_ci	 * left aligned formats: rotate w/ sample_width
80862306a36Sopenharmony_ci	 *
80962306a36Sopenharmony_ci	 * RX rotation:
81062306a36Sopenharmony_ci	 * right aligned formats: no rotation needed
81162306a36Sopenharmony_ci	 * left aligned formats: rotate w/ (slot_width - sample_width)
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
81462306a36Sopenharmony_ci	    SND_SOC_DAIFMT_RIGHT_J) {
81562306a36Sopenharmony_ci		tx_rotate = (slot_width / 4) & 0x7;
81662306a36Sopenharmony_ci		rx_rotate = 0;
81762306a36Sopenharmony_ci	} else {
81862306a36Sopenharmony_ci		tx_rotate = (sample_width / 4) & 0x7;
81962306a36Sopenharmony_ci		rx_rotate = (slot_width - sample_width) / 4;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	/* mapping of the XSSZ bit-field as described in the datasheet */
82362306a36Sopenharmony_ci	fmt = (slot_width >> 1) - 1;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
82662306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
82762306a36Sopenharmony_ci			       RXSSZ(0x0F));
82862306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
82962306a36Sopenharmony_ci			       TXSSZ(0x0F));
83062306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
83162306a36Sopenharmony_ci			       TXROT(7));
83262306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
83362306a36Sopenharmony_ci			       RXROT(7));
83462306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
83562306a36Sopenharmony_ci	} else {
83662306a36Sopenharmony_ci		/*
83762306a36Sopenharmony_ci		 * according to the TRM it should be TXROT=0, this one works:
83862306a36Sopenharmony_ci		 * 16 bit to 23-8 (TXROT=6, rotate 24 bits)
83962306a36Sopenharmony_ci		 * 24 bit to 23-0 (TXROT=0, rotate 0 bits)
84062306a36Sopenharmony_ci		 *
84162306a36Sopenharmony_ci		 * TXROT = 0 only works with 24bit samples
84262306a36Sopenharmony_ci		 */
84362306a36Sopenharmony_ci		tx_rotate = (sample_width / 4 + 2) & 0x7;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
84662306a36Sopenharmony_ci			       TXROT(7));
84762306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
84862306a36Sopenharmony_ci			       TXSSZ(0x0F));
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
85762306a36Sopenharmony_ci				 int period_words, int channels)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
86062306a36Sopenharmony_ci	int i;
86162306a36Sopenharmony_ci	u8 tx_ser = 0;
86262306a36Sopenharmony_ci	u8 rx_ser = 0;
86362306a36Sopenharmony_ci	u8 slots = mcasp->tdm_slots;
86462306a36Sopenharmony_ci	u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
86562306a36Sopenharmony_ci	int active_serializers, numevt;
86662306a36Sopenharmony_ci	u32 reg;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* In DIT mode we only allow maximum of one serializers for now */
86962306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
87062306a36Sopenharmony_ci		max_active_serializers = 1;
87162306a36Sopenharmony_ci	else
87262306a36Sopenharmony_ci		max_active_serializers = DIV_ROUND_UP(channels, slots);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* Default configuration */
87562306a36Sopenharmony_ci	if (mcasp->version < MCASP_VERSION_3)
87662306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
87962306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
88062306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
88162306a36Sopenharmony_ci		max_tx_serializers = max_active_serializers;
88262306a36Sopenharmony_ci		max_rx_serializers =
88362306a36Sopenharmony_ci			mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE];
88462306a36Sopenharmony_ci	} else {
88562306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
88662306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
88762306a36Sopenharmony_ci		max_tx_serializers =
88862306a36Sopenharmony_ci			mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK];
88962306a36Sopenharmony_ci		max_rx_serializers = max_active_serializers;
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++) {
89362306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
89462306a36Sopenharmony_ci			       mcasp->serial_dir[i]);
89562306a36Sopenharmony_ci		if (mcasp->serial_dir[i] == TX_MODE &&
89662306a36Sopenharmony_ci					tx_ser < max_tx_serializers) {
89762306a36Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
89862306a36Sopenharmony_ci				       mcasp->dismod, DISMOD_MASK);
89962306a36Sopenharmony_ci			set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
90062306a36Sopenharmony_ci			tx_ser++;
90162306a36Sopenharmony_ci		} else if (mcasp->serial_dir[i] == RX_MODE &&
90262306a36Sopenharmony_ci					rx_ser < max_rx_serializers) {
90362306a36Sopenharmony_ci			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
90462306a36Sopenharmony_ci			rx_ser++;
90562306a36Sopenharmony_ci		} else {
90662306a36Sopenharmony_ci			/* Inactive or unused pin, set it to inactive */
90762306a36Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
90862306a36Sopenharmony_ci				       SRMOD_INACTIVE, SRMOD_MASK);
90962306a36Sopenharmony_ci			/* If unused, set DISMOD for the pin */
91062306a36Sopenharmony_ci			if (mcasp->serial_dir[i] != INACTIVE_MODE)
91162306a36Sopenharmony_ci				mcasp_mod_bits(mcasp,
91262306a36Sopenharmony_ci					       DAVINCI_MCASP_XRSRCTL_REG(i),
91362306a36Sopenharmony_ci					       mcasp->dismod, DISMOD_MASK);
91462306a36Sopenharmony_ci			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
91962306a36Sopenharmony_ci		active_serializers = tx_ser;
92062306a36Sopenharmony_ci		numevt = mcasp->txnumevt;
92162306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
92262306a36Sopenharmony_ci	} else {
92362306a36Sopenharmony_ci		active_serializers = rx_ser;
92462306a36Sopenharmony_ci		numevt = mcasp->rxnumevt;
92562306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (active_serializers < max_active_serializers) {
92962306a36Sopenharmony_ci		dev_warn(mcasp->dev, "stream has more channels (%d) than are "
93062306a36Sopenharmony_ci			 "enabled in mcasp (%d)\n", channels,
93162306a36Sopenharmony_ci			 active_serializers * slots);
93262306a36Sopenharmony_ci		return -EINVAL;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* AFIFO is not in use */
93662306a36Sopenharmony_ci	if (!numevt) {
93762306a36Sopenharmony_ci		/* Configure the burst size for platform drivers */
93862306a36Sopenharmony_ci		if (active_serializers > 1) {
93962306a36Sopenharmony_ci			/*
94062306a36Sopenharmony_ci			 * If more than one serializers are in use we have one
94162306a36Sopenharmony_ci			 * DMA request to provide data for all serializers.
94262306a36Sopenharmony_ci			 * For example if three serializers are enabled the DMA
94362306a36Sopenharmony_ci			 * need to transfer three words per DMA request.
94462306a36Sopenharmony_ci			 */
94562306a36Sopenharmony_ci			dma_data->maxburst = active_serializers;
94662306a36Sopenharmony_ci		} else {
94762306a36Sopenharmony_ci			dma_data->maxburst = 0;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		goto out;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (period_words % active_serializers) {
95462306a36Sopenharmony_ci		dev_err(mcasp->dev, "Invalid combination of period words and "
95562306a36Sopenharmony_ci			"active serializers: %d, %d\n", period_words,
95662306a36Sopenharmony_ci			active_serializers);
95762306a36Sopenharmony_ci		return -EINVAL;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	/*
96162306a36Sopenharmony_ci	 * Calculate the optimal AFIFO depth for platform side:
96262306a36Sopenharmony_ci	 * The number of words for numevt need to be in steps of active
96362306a36Sopenharmony_ci	 * serializers.
96462306a36Sopenharmony_ci	 */
96562306a36Sopenharmony_ci	numevt = (numevt / active_serializers) * active_serializers;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	while (period_words % numevt && numevt > 0)
96862306a36Sopenharmony_ci		numevt -= active_serializers;
96962306a36Sopenharmony_ci	if (numevt <= 0)
97062306a36Sopenharmony_ci		numevt = active_serializers;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
97362306a36Sopenharmony_ci	mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/* Configure the burst size for platform drivers */
97662306a36Sopenharmony_ci	if (numevt == 1)
97762306a36Sopenharmony_ci		numevt = 0;
97862306a36Sopenharmony_ci	dma_data->maxburst = numevt;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ciout:
98162306a36Sopenharmony_ci	mcasp->active_serializers[stream] = active_serializers;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return 0;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
98762306a36Sopenharmony_ci			      int channels)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	int i, active_slots;
99062306a36Sopenharmony_ci	int total_slots;
99162306a36Sopenharmony_ci	int active_serializers;
99262306a36Sopenharmony_ci	u32 mask = 0;
99362306a36Sopenharmony_ci	u32 busel = 0;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	total_slots = mcasp->tdm_slots;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/*
99862306a36Sopenharmony_ci	 * If more than one serializer is needed, then use them with
99962306a36Sopenharmony_ci	 * all the specified tdm_slots. Otherwise, one serializer can
100062306a36Sopenharmony_ci	 * cope with the transaction using just as many slots as there
100162306a36Sopenharmony_ci	 * are channels in the stream.
100262306a36Sopenharmony_ci	 */
100362306a36Sopenharmony_ci	if (mcasp->tdm_mask[stream]) {
100462306a36Sopenharmony_ci		active_slots = hweight32(mcasp->tdm_mask[stream]);
100562306a36Sopenharmony_ci		active_serializers = DIV_ROUND_UP(channels, active_slots);
100662306a36Sopenharmony_ci		if (active_serializers == 1)
100762306a36Sopenharmony_ci			active_slots = channels;
100862306a36Sopenharmony_ci		for (i = 0; i < total_slots; i++) {
100962306a36Sopenharmony_ci			if ((1 << i) & mcasp->tdm_mask[stream]) {
101062306a36Sopenharmony_ci				mask |= (1 << i);
101162306a36Sopenharmony_ci				if (--active_slots <= 0)
101262306a36Sopenharmony_ci					break;
101362306a36Sopenharmony_ci			}
101462306a36Sopenharmony_ci		}
101562306a36Sopenharmony_ci	} else {
101662306a36Sopenharmony_ci		active_serializers = DIV_ROUND_UP(channels, total_slots);
101762306a36Sopenharmony_ci		if (active_serializers == 1)
101862306a36Sopenharmony_ci			active_slots = channels;
101962306a36Sopenharmony_ci		else
102062306a36Sopenharmony_ci			active_slots = total_slots;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		for (i = 0; i < active_slots; i++)
102362306a36Sopenharmony_ci			mask |= (1 << i);
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (!mcasp->dat_port)
102962306a36Sopenharmony_ci		busel = TXSEL;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
103262306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
103362306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
103462306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
103562306a36Sopenharmony_ci			       FSXMOD(total_slots), FSXMOD(0x1FF));
103662306a36Sopenharmony_ci	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
103762306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
103862306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
103962306a36Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
104062306a36Sopenharmony_ci			       FSRMOD(total_slots), FSRMOD(0x1FF));
104162306a36Sopenharmony_ci		/*
104262306a36Sopenharmony_ci		 * If McASP is set to be TX/RX synchronous and the playback is
104362306a36Sopenharmony_ci		 * not running already we need to configure the TX slots in
104462306a36Sopenharmony_ci		 * order to have correct FSX on the bus
104562306a36Sopenharmony_ci		 */
104662306a36Sopenharmony_ci		if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
104762306a36Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
104862306a36Sopenharmony_ci				       FSXMOD(total_slots), FSXMOD(0x1FF));
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return 0;
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci/* S/PDIF */
105562306a36Sopenharmony_cistatic int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
105662306a36Sopenharmony_ci			      unsigned int rate)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	u8 *cs_bytes = (u8 *)&mcasp->iec958_status;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (!mcasp->dat_port)
106162306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
106262306a36Sopenharmony_ci	else
106362306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
106662306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	/* Set the TX tdm : for all the slots */
107162306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/* Set the TX clock controls : div = 1 and internal */
107462306a36Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	/* Set S/PDIF channel status bits */
107962306a36Sopenharmony_ci	cs_bytes[3] &= ~IEC958_AES3_CON_FS;
108062306a36Sopenharmony_ci	switch (rate) {
108162306a36Sopenharmony_ci	case 22050:
108262306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
108362306a36Sopenharmony_ci		break;
108462306a36Sopenharmony_ci	case 24000:
108562306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
108662306a36Sopenharmony_ci		break;
108762306a36Sopenharmony_ci	case 32000:
108862306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
108962306a36Sopenharmony_ci		break;
109062306a36Sopenharmony_ci	case 44100:
109162306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
109262306a36Sopenharmony_ci		break;
109362306a36Sopenharmony_ci	case 48000:
109462306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci	case 88200:
109762306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
109862306a36Sopenharmony_ci		break;
109962306a36Sopenharmony_ci	case 96000:
110062306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	case 176400:
110362306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
110462306a36Sopenharmony_ci		break;
110562306a36Sopenharmony_ci	case 192000:
110662306a36Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
110762306a36Sopenharmony_ci		break;
110862306a36Sopenharmony_ci	default:
110962306a36Sopenharmony_ci		dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
111062306a36Sopenharmony_ci		return -EINVAL;
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
111462306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	/* Enable the DIT */
111762306a36Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	return 0;
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
112362306a36Sopenharmony_ci				      unsigned int sysclk_freq,
112462306a36Sopenharmony_ci				      unsigned int bclk_freq, bool set)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
112762306a36Sopenharmony_ci	int div = sysclk_freq / bclk_freq;
112862306a36Sopenharmony_ci	int rem = sysclk_freq % bclk_freq;
112962306a36Sopenharmony_ci	int error_ppm;
113062306a36Sopenharmony_ci	int aux_div = 1;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	if (div > (ACLKXDIV_MASK + 1)) {
113362306a36Sopenharmony_ci		if (reg & AHCLKXE) {
113462306a36Sopenharmony_ci			aux_div = div / (ACLKXDIV_MASK + 1);
113562306a36Sopenharmony_ci			if (div % (ACLKXDIV_MASK + 1))
113662306a36Sopenharmony_ci				aux_div++;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci			sysclk_freq /= aux_div;
113962306a36Sopenharmony_ci			div = sysclk_freq / bclk_freq;
114062306a36Sopenharmony_ci			rem = sysclk_freq % bclk_freq;
114162306a36Sopenharmony_ci		} else if (set) {
114262306a36Sopenharmony_ci			dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
114362306a36Sopenharmony_ci				 sysclk_freq);
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	if (rem != 0) {
114862306a36Sopenharmony_ci		if (div == 0 ||
114962306a36Sopenharmony_ci		    ((sysclk_freq / div) - bclk_freq) >
115062306a36Sopenharmony_ci		    (bclk_freq - (sysclk_freq / (div+1)))) {
115162306a36Sopenharmony_ci			div++;
115262306a36Sopenharmony_ci			rem = rem - bclk_freq;
115362306a36Sopenharmony_ci		}
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci	error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
115662306a36Sopenharmony_ci		     (int)bclk_freq)) / div - 1000000;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (set) {
115962306a36Sopenharmony_ci		if (error_ppm)
116062306a36Sopenharmony_ci			dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
116162306a36Sopenharmony_ci				 error_ppm);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
116462306a36Sopenharmony_ci		if (reg & AHCLKXE)
116562306a36Sopenharmony_ci			__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
116662306a36Sopenharmony_ci						   aux_div, 0);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	return error_ppm;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	if (!mcasp->txnumevt)
117562306a36Sopenharmony_ci		return 0;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	if (!mcasp->rxnumevt)
118362306a36Sopenharmony_ci		return 0;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic snd_pcm_sframes_t davinci_mcasp_delay(
118962306a36Sopenharmony_ci			struct snd_pcm_substream *substream,
119062306a36Sopenharmony_ci			struct snd_soc_dai *cpu_dai)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
119362306a36Sopenharmony_ci	u32 fifo_use;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
119662306a36Sopenharmony_ci		fifo_use = davinci_mcasp_tx_delay(mcasp);
119762306a36Sopenharmony_ci	else
119862306a36Sopenharmony_ci		fifo_use = davinci_mcasp_rx_delay(mcasp);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/*
120162306a36Sopenharmony_ci	 * Divide the used locations with the channel count to get the
120262306a36Sopenharmony_ci	 * FIFO usage in samples (don't care about partial samples in the
120362306a36Sopenharmony_ci	 * buffer).
120462306a36Sopenharmony_ci	 */
120562306a36Sopenharmony_ci	return fifo_use / substream->runtime->channels;
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
120962306a36Sopenharmony_ci					struct snd_pcm_hw_params *params,
121062306a36Sopenharmony_ci					struct snd_soc_dai *cpu_dai)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
121362306a36Sopenharmony_ci	int word_length;
121462306a36Sopenharmony_ci	int channels = params_channels(params);
121562306a36Sopenharmony_ci	int period_size = params_period_size(params);
121662306a36Sopenharmony_ci	int ret;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	switch (params_format(params)) {
121962306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U8:
122062306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
122162306a36Sopenharmony_ci		word_length = 8;
122262306a36Sopenharmony_ci		break;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U16_LE:
122562306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
122662306a36Sopenharmony_ci		word_length = 16;
122762306a36Sopenharmony_ci		break;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U24_3LE:
123062306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_3LE:
123162306a36Sopenharmony_ci		word_length = 24;
123262306a36Sopenharmony_ci		break;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U24_LE:
123562306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
123662306a36Sopenharmony_ci		word_length = 24;
123762306a36Sopenharmony_ci		break;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U32_LE:
124062306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
124162306a36Sopenharmony_ci		word_length = 32;
124262306a36Sopenharmony_ci		break;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	default:
124562306a36Sopenharmony_ci		printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
124662306a36Sopenharmony_ci		return -EINVAL;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt);
125062306a36Sopenharmony_ci	if (ret)
125162306a36Sopenharmony_ci		return ret;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	/*
125462306a36Sopenharmony_ci	 * If mcasp is BCLK master, and a BCLK divider was not provided by
125562306a36Sopenharmony_ci	 * the machine driver, we need to calculate the ratio.
125662306a36Sopenharmony_ci	 */
125762306a36Sopenharmony_ci	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
125862306a36Sopenharmony_ci		int slots = mcasp->tdm_slots;
125962306a36Sopenharmony_ci		int rate = params_rate(params);
126062306a36Sopenharmony_ci		int sbits = params_width(params);
126162306a36Sopenharmony_ci		unsigned int bclk_target;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		if (mcasp->slot_width)
126462306a36Sopenharmony_ci			sbits = mcasp->slot_width;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci		if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
126762306a36Sopenharmony_ci			bclk_target = rate * sbits * slots;
126862306a36Sopenharmony_ci		else
126962306a36Sopenharmony_ci			bclk_target = rate * 128;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci		davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
127262306a36Sopenharmony_ci					   bclk_target, true);
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	ret = mcasp_common_hw_param(mcasp, substream->stream,
127662306a36Sopenharmony_ci				    period_size * channels, channels);
127762306a36Sopenharmony_ci	if (ret)
127862306a36Sopenharmony_ci		return ret;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
128162306a36Sopenharmony_ci		ret = mcasp_dit_hw_param(mcasp, params_rate(params));
128262306a36Sopenharmony_ci	else
128362306a36Sopenharmony_ci		ret = mcasp_i2s_hw_param(mcasp, substream->stream,
128462306a36Sopenharmony_ci					 channels);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (ret)
128762306a36Sopenharmony_ci		return ret;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	davinci_config_channel_size(mcasp, word_length);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
129262306a36Sopenharmony_ci		mcasp->channels = channels;
129362306a36Sopenharmony_ci		if (!mcasp->max_format_width)
129462306a36Sopenharmony_ci			mcasp->max_format_width = word_length;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	return 0;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
130162306a36Sopenharmony_ci				     int cmd, struct snd_soc_dai *cpu_dai)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
130462306a36Sopenharmony_ci	int ret = 0;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	switch (cmd) {
130762306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
130862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
130962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
131062306a36Sopenharmony_ci		davinci_mcasp_start(mcasp, substream->stream);
131162306a36Sopenharmony_ci		break;
131262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
131362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
131462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
131562306a36Sopenharmony_ci		davinci_mcasp_stop(mcasp, substream->stream);
131662306a36Sopenharmony_ci		break;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	default:
131962306a36Sopenharmony_ci		ret = -EINVAL;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return ret;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
132662306a36Sopenharmony_ci					    struct snd_pcm_hw_rule *rule)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
132962306a36Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
133062306a36Sopenharmony_ci	struct snd_mask nfmt;
133162306a36Sopenharmony_ci	int slot_width;
133262306a36Sopenharmony_ci	snd_pcm_format_t i;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	snd_mask_none(&nfmt);
133562306a36Sopenharmony_ci	slot_width = rd->mcasp->slot_width;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	pcm_for_each_format(i) {
133862306a36Sopenharmony_ci		if (snd_mask_test_format(fmt, i)) {
133962306a36Sopenharmony_ci			if (snd_pcm_format_width(i) <= slot_width) {
134062306a36Sopenharmony_ci				snd_mask_set_format(&nfmt, i);
134162306a36Sopenharmony_ci			}
134262306a36Sopenharmony_ci		}
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params,
134962306a36Sopenharmony_ci					      struct snd_pcm_hw_rule *rule)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
135262306a36Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
135362306a36Sopenharmony_ci	struct snd_mask nfmt;
135462306a36Sopenharmony_ci	int format_width;
135562306a36Sopenharmony_ci	snd_pcm_format_t i;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	snd_mask_none(&nfmt);
135862306a36Sopenharmony_ci	format_width = rd->mcasp->max_format_width;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	pcm_for_each_format(i) {
136162306a36Sopenharmony_ci		if (snd_mask_test_format(fmt, i)) {
136262306a36Sopenharmony_ci			if (snd_pcm_format_width(i) == format_width) {
136362306a36Sopenharmony_ci				snd_mask_set_format(&nfmt, i);
136462306a36Sopenharmony_ci			}
136562306a36Sopenharmony_ci		}
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic const unsigned int davinci_mcasp_dai_rates[] = {
137262306a36Sopenharmony_ci	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
137362306a36Sopenharmony_ci	88200, 96000, 176400, 192000,
137462306a36Sopenharmony_ci};
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci#define DAVINCI_MAX_RATE_ERROR_PPM 1000
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
137962306a36Sopenharmony_ci				      struct snd_pcm_hw_rule *rule)
138062306a36Sopenharmony_ci{
138162306a36Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
138262306a36Sopenharmony_ci	struct snd_interval *ri =
138362306a36Sopenharmony_ci		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
138462306a36Sopenharmony_ci	int sbits = params_width(params);
138562306a36Sopenharmony_ci	int slots = rd->mcasp->tdm_slots;
138662306a36Sopenharmony_ci	struct snd_interval range;
138762306a36Sopenharmony_ci	int i;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (rd->mcasp->slot_width)
139062306a36Sopenharmony_ci		sbits = rd->mcasp->slot_width;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	snd_interval_any(&range);
139362306a36Sopenharmony_ci	range.empty = 1;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
139662306a36Sopenharmony_ci		if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
139762306a36Sopenharmony_ci			uint bclk_freq = sbits * slots *
139862306a36Sopenharmony_ci					 davinci_mcasp_dai_rates[i];
139962306a36Sopenharmony_ci			unsigned int sysclk_freq;
140062306a36Sopenharmony_ci			int ppm;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci			if (rd->mcasp->auxclk_fs_ratio)
140362306a36Sopenharmony_ci				sysclk_freq =  davinci_mcasp_dai_rates[i] *
140462306a36Sopenharmony_ci					       rd->mcasp->auxclk_fs_ratio;
140562306a36Sopenharmony_ci			else
140662306a36Sopenharmony_ci				sysclk_freq = rd->mcasp->sysclk_freq;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
140962306a36Sopenharmony_ci							 bclk_freq, false);
141062306a36Sopenharmony_ci			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
141162306a36Sopenharmony_ci				if (range.empty) {
141262306a36Sopenharmony_ci					range.min = davinci_mcasp_dai_rates[i];
141362306a36Sopenharmony_ci					range.empty = 0;
141462306a36Sopenharmony_ci				}
141562306a36Sopenharmony_ci				range.max = davinci_mcasp_dai_rates[i];
141662306a36Sopenharmony_ci			}
141762306a36Sopenharmony_ci		}
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	dev_dbg(rd->mcasp->dev,
142162306a36Sopenharmony_ci		"Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
142262306a36Sopenharmony_ci		ri->min, ri->max, range.min, range.max, sbits, slots);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, rule->var),
142562306a36Sopenharmony_ci				   &range);
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
142962306a36Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
143262306a36Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
143362306a36Sopenharmony_ci	struct snd_mask nfmt;
143462306a36Sopenharmony_ci	int rate = params_rate(params);
143562306a36Sopenharmony_ci	int slots = rd->mcasp->tdm_slots;
143662306a36Sopenharmony_ci	int count = 0;
143762306a36Sopenharmony_ci	snd_pcm_format_t i;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	snd_mask_none(&nfmt);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	pcm_for_each_format(i) {
144262306a36Sopenharmony_ci		if (snd_mask_test_format(fmt, i)) {
144362306a36Sopenharmony_ci			uint sbits = snd_pcm_format_width(i);
144462306a36Sopenharmony_ci			unsigned int sysclk_freq;
144562306a36Sopenharmony_ci			int ppm;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci			if (rd->mcasp->auxclk_fs_ratio)
144862306a36Sopenharmony_ci				sysclk_freq =  rate *
144962306a36Sopenharmony_ci					       rd->mcasp->auxclk_fs_ratio;
145062306a36Sopenharmony_ci			else
145162306a36Sopenharmony_ci				sysclk_freq = rd->mcasp->sysclk_freq;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci			if (rd->mcasp->slot_width)
145462306a36Sopenharmony_ci				sbits = rd->mcasp->slot_width;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
145762306a36Sopenharmony_ci							 sbits * slots * rate,
145862306a36Sopenharmony_ci							 false);
145962306a36Sopenharmony_ci			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
146062306a36Sopenharmony_ci				snd_mask_set_format(&nfmt, i);
146162306a36Sopenharmony_ci				count++;
146262306a36Sopenharmony_ci			}
146362306a36Sopenharmony_ci		}
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci	dev_dbg(rd->mcasp->dev,
146662306a36Sopenharmony_ci		"%d possible sample format for %d Hz and %d tdm slots\n",
146762306a36Sopenharmony_ci		count, rate, slots);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_min_periodsize(
147362306a36Sopenharmony_ci		struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct snd_interval *period_size = hw_param_interval(params,
147662306a36Sopenharmony_ci						SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
147762306a36Sopenharmony_ci	struct snd_interval frames;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	snd_interval_any(&frames);
148062306a36Sopenharmony_ci	frames.min = 64;
148162306a36Sopenharmony_ci	frames.integer = 1;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	return snd_interval_refine(period_size, &frames);
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_cistatic int davinci_mcasp_startup(struct snd_pcm_substream *substream,
148762306a36Sopenharmony_ci				 struct snd_soc_dai *cpu_dai)
148862306a36Sopenharmony_ci{
148962306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
149062306a36Sopenharmony_ci	struct davinci_mcasp_ruledata *ruledata =
149162306a36Sopenharmony_ci					&mcasp->ruledata[substream->stream];
149262306a36Sopenharmony_ci	u32 max_channels = 0;
149362306a36Sopenharmony_ci	int i, dir, ret;
149462306a36Sopenharmony_ci	int tdm_slots = mcasp->tdm_slots;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	/* Do not allow more then one stream per direction */
149762306a36Sopenharmony_ci	if (mcasp->substreams[substream->stream])
149862306a36Sopenharmony_ci		return -EBUSY;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	mcasp->substreams[substream->stream] = substream;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	if (mcasp->tdm_mask[substream->stream])
150362306a36Sopenharmony_ci		tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
150662306a36Sopenharmony_ci		return 0;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/*
150962306a36Sopenharmony_ci	 * Limit the maximum allowed channels for the first stream:
151062306a36Sopenharmony_ci	 * number of serializers for the direction * tdm slots per serializer
151162306a36Sopenharmony_ci	 */
151262306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
151362306a36Sopenharmony_ci		dir = TX_MODE;
151462306a36Sopenharmony_ci	else
151562306a36Sopenharmony_ci		dir = RX_MODE;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++) {
151862306a36Sopenharmony_ci		if (mcasp->serial_dir[i] == dir)
151962306a36Sopenharmony_ci			max_channels++;
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci	ruledata->serializers = max_channels;
152262306a36Sopenharmony_ci	ruledata->mcasp = mcasp;
152362306a36Sopenharmony_ci	max_channels *= tdm_slots;
152462306a36Sopenharmony_ci	/*
152562306a36Sopenharmony_ci	 * If the already active stream has less channels than the calculated
152662306a36Sopenharmony_ci	 * limit based on the seirializers * tdm_slots, and only one serializer
152762306a36Sopenharmony_ci	 * is in use we need to use that as a constraint for the second stream.
152862306a36Sopenharmony_ci	 * Otherwise (first stream or less allowed channels or more than one
152962306a36Sopenharmony_ci	 * serializer in use) we use the calculated constraint.
153062306a36Sopenharmony_ci	 */
153162306a36Sopenharmony_ci	if (mcasp->channels && mcasp->channels < max_channels &&
153262306a36Sopenharmony_ci	    ruledata->serializers == 1)
153362306a36Sopenharmony_ci		max_channels = mcasp->channels;
153462306a36Sopenharmony_ci	/*
153562306a36Sopenharmony_ci	 * But we can always allow channels upto the amount of
153662306a36Sopenharmony_ci	 * the available tdm_slots.
153762306a36Sopenharmony_ci	 */
153862306a36Sopenharmony_ci	if (max_channels < tdm_slots)
153962306a36Sopenharmony_ci		max_channels = tdm_slots;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	snd_pcm_hw_constraint_minmax(substream->runtime,
154262306a36Sopenharmony_ci				     SNDRV_PCM_HW_PARAM_CHANNELS,
154362306a36Sopenharmony_ci				     0, max_channels);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(substream->runtime,
154662306a36Sopenharmony_ci				   0, SNDRV_PCM_HW_PARAM_CHANNELS,
154762306a36Sopenharmony_ci				   &mcasp->chconstr[substream->stream]);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (mcasp->max_format_width) {
155062306a36Sopenharmony_ci		/*
155162306a36Sopenharmony_ci		 * Only allow formats which require same amount of bits on the
155262306a36Sopenharmony_ci		 * bus as the currently running stream
155362306a36Sopenharmony_ci		 */
155462306a36Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
155562306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
155662306a36Sopenharmony_ci					  davinci_mcasp_hw_rule_format_width,
155762306a36Sopenharmony_ci					  ruledata,
155862306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
155962306a36Sopenharmony_ci		if (ret)
156062306a36Sopenharmony_ci			return ret;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci	else if (mcasp->slot_width) {
156362306a36Sopenharmony_ci		/* Only allow formats require <= slot_width bits on the bus */
156462306a36Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
156562306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
156662306a36Sopenharmony_ci					  davinci_mcasp_hw_rule_slot_width,
156762306a36Sopenharmony_ci					  ruledata,
156862306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
156962306a36Sopenharmony_ci		if (ret)
157062306a36Sopenharmony_ci			return ret;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/*
157462306a36Sopenharmony_ci	 * If we rely on implicit BCLK divider setting we should
157562306a36Sopenharmony_ci	 * set constraints based on what we can provide.
157662306a36Sopenharmony_ci	 */
157762306a36Sopenharmony_ci	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
157862306a36Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
157962306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_RATE,
158062306a36Sopenharmony_ci					  davinci_mcasp_hw_rule_rate,
158162306a36Sopenharmony_ci					  ruledata,
158262306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
158362306a36Sopenharmony_ci		if (ret)
158462306a36Sopenharmony_ci			return ret;
158562306a36Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
158662306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
158762306a36Sopenharmony_ci					  davinci_mcasp_hw_rule_format,
158862306a36Sopenharmony_ci					  ruledata,
158962306a36Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_RATE, -1);
159062306a36Sopenharmony_ci		if (ret)
159162306a36Sopenharmony_ci			return ret;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	snd_pcm_hw_rule_add(substream->runtime, 0,
159562306a36Sopenharmony_ci			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
159662306a36Sopenharmony_ci			    davinci_mcasp_hw_rule_min_periodsize, NULL,
159762306a36Sopenharmony_ci			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	return 0;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
160362306a36Sopenharmony_ci				   struct snd_soc_dai *cpu_dai)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	mcasp->substreams[substream->stream] = NULL;
160862306a36Sopenharmony_ci	mcasp->active_serializers[substream->stream] = 0;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
161162306a36Sopenharmony_ci		return;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	if (!snd_soc_dai_active(cpu_dai)) {
161462306a36Sopenharmony_ci		mcasp->channels = 0;
161562306a36Sopenharmony_ci		mcasp->max_format_width = 0;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_cistatic int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
162062306a36Sopenharmony_ci				     struct snd_ctl_elem_info *uinfo)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
162362306a36Sopenharmony_ci	uinfo->count = 1;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	return 0;
162662306a36Sopenharmony_ci}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_cistatic int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
162962306a36Sopenharmony_ci				    struct snd_ctl_elem_value *uctl)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
163262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
163562306a36Sopenharmony_ci	       sizeof(mcasp->iec958_status));
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	return 0;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
164162306a36Sopenharmony_ci				    struct snd_ctl_elem_value *uctl)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
164462306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
164762306a36Sopenharmony_ci	       sizeof(mcasp->iec958_status));
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	return 0;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_cistatic int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
165362306a36Sopenharmony_ci					     struct snd_ctl_elem_value *ucontrol)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
165662306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
166362306a36Sopenharmony_ci	{
166462306a36Sopenharmony_ci		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
166562306a36Sopenharmony_ci			   SNDRV_CTL_ELEM_ACCESS_VOLATILE),
166662306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
166762306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
166862306a36Sopenharmony_ci		.info = davinci_mcasp_iec958_info,
166962306a36Sopenharmony_ci		.get = davinci_mcasp_iec958_get,
167062306a36Sopenharmony_ci		.put = davinci_mcasp_iec958_put,
167162306a36Sopenharmony_ci	}, {
167262306a36Sopenharmony_ci		.access = SNDRV_CTL_ELEM_ACCESS_READ,
167362306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
167462306a36Sopenharmony_ci		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
167562306a36Sopenharmony_ci		.info = davinci_mcasp_iec958_info,
167662306a36Sopenharmony_ci		.get = davinci_mcasp_iec958_con_mask_get,
167762306a36Sopenharmony_ci	},
167862306a36Sopenharmony_ci};
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	unsigned char *cs = (u8 *)&mcasp->iec958_status;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
168562306a36Sopenharmony_ci	cs[1] = IEC958_AES1_CON_PCM_CODER;
168662306a36Sopenharmony_ci	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
168762306a36Sopenharmony_ci	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistatic int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
169362306a36Sopenharmony_ci	int stream;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	for_each_pcm_streams(stream)
169662306a36Sopenharmony_ci		snd_soc_dai_dma_data_set(dai, stream, &mcasp->dma_data[stream]);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
169962306a36Sopenharmony_ci		davinci_mcasp_init_iec958_status(mcasp);
170062306a36Sopenharmony_ci		snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
170162306a36Sopenharmony_ci					 ARRAY_SIZE(davinci_mcasp_iec958_ctls));
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	return 0;
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
170862306a36Sopenharmony_ci	.probe		= davinci_mcasp_dai_probe,
170962306a36Sopenharmony_ci	.startup	= davinci_mcasp_startup,
171062306a36Sopenharmony_ci	.shutdown	= davinci_mcasp_shutdown,
171162306a36Sopenharmony_ci	.trigger	= davinci_mcasp_trigger,
171262306a36Sopenharmony_ci	.delay		= davinci_mcasp_delay,
171362306a36Sopenharmony_ci	.hw_params	= davinci_mcasp_hw_params,
171462306a36Sopenharmony_ci	.set_fmt	= davinci_mcasp_set_dai_fmt,
171562306a36Sopenharmony_ci	.set_clkdiv	= davinci_mcasp_set_clkdiv,
171662306a36Sopenharmony_ci	.set_sysclk	= davinci_mcasp_set_sysclk,
171762306a36Sopenharmony_ci	.set_tdm_slot	= davinci_mcasp_set_tdm_slot,
171862306a36Sopenharmony_ci};
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci#define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_192000
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
172362306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_U8 | \
172462306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_S16_LE | \
172562306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_U16_LE | \
172662306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_LE | \
172762306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_U24_LE | \
172862306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_3LE | \
172962306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_U24_3LE | \
173062306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_S32_LE | \
173162306a36Sopenharmony_ci				SNDRV_PCM_FMTBIT_U32_LE)
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_cistatic struct snd_soc_dai_driver davinci_mcasp_dai[] = {
173462306a36Sopenharmony_ci	{
173562306a36Sopenharmony_ci		.name		= "davinci-mcasp.0",
173662306a36Sopenharmony_ci		.playback	= {
173762306a36Sopenharmony_ci			.stream_name = "IIS Playback",
173862306a36Sopenharmony_ci			.channels_min	= 1,
173962306a36Sopenharmony_ci			.channels_max	= 32 * 16,
174062306a36Sopenharmony_ci			.rates 		= DAVINCI_MCASP_RATES,
174162306a36Sopenharmony_ci			.formats	= DAVINCI_MCASP_PCM_FMTS,
174262306a36Sopenharmony_ci		},
174362306a36Sopenharmony_ci		.capture 	= {
174462306a36Sopenharmony_ci			.stream_name = "IIS Capture",
174562306a36Sopenharmony_ci			.channels_min 	= 1,
174662306a36Sopenharmony_ci			.channels_max	= 32 * 16,
174762306a36Sopenharmony_ci			.rates 		= DAVINCI_MCASP_RATES,
174862306a36Sopenharmony_ci			.formats	= DAVINCI_MCASP_PCM_FMTS,
174962306a36Sopenharmony_ci		},
175062306a36Sopenharmony_ci		.ops 		= &davinci_mcasp_dai_ops,
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		.symmetric_rate		= 1,
175362306a36Sopenharmony_ci	},
175462306a36Sopenharmony_ci	{
175562306a36Sopenharmony_ci		.name		= "davinci-mcasp.1",
175662306a36Sopenharmony_ci		.playback 	= {
175762306a36Sopenharmony_ci			.stream_name = "DIT Playback",
175862306a36Sopenharmony_ci			.channels_min	= 1,
175962306a36Sopenharmony_ci			.channels_max	= 384,
176062306a36Sopenharmony_ci			.rates		= DAVINCI_MCASP_RATES,
176162306a36Sopenharmony_ci			.formats	= SNDRV_PCM_FMTBIT_S16_LE |
176262306a36Sopenharmony_ci					  SNDRV_PCM_FMTBIT_S24_LE,
176362306a36Sopenharmony_ci		},
176462306a36Sopenharmony_ci		.ops 		= &davinci_mcasp_dai_ops,
176562306a36Sopenharmony_ci	},
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci};
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_cistatic const struct snd_soc_component_driver davinci_mcasp_component = {
177062306a36Sopenharmony_ci	.name			= "davinci-mcasp",
177162306a36Sopenharmony_ci	.legacy_dai_naming	= 1,
177262306a36Sopenharmony_ci};
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci/* Some HW specific values and defaults. The rest is filled in from DT. */
177562306a36Sopenharmony_cistatic struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
177662306a36Sopenharmony_ci	.tx_dma_offset = 0x400,
177762306a36Sopenharmony_ci	.rx_dma_offset = 0x400,
177862306a36Sopenharmony_ci	.version = MCASP_VERSION_1,
177962306a36Sopenharmony_ci};
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic struct davinci_mcasp_pdata da830_mcasp_pdata = {
178262306a36Sopenharmony_ci	.tx_dma_offset = 0x2000,
178362306a36Sopenharmony_ci	.rx_dma_offset = 0x2000,
178462306a36Sopenharmony_ci	.version = MCASP_VERSION_2,
178562306a36Sopenharmony_ci};
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
178862306a36Sopenharmony_ci	.tx_dma_offset = 0,
178962306a36Sopenharmony_ci	.rx_dma_offset = 0,
179062306a36Sopenharmony_ci	.version = MCASP_VERSION_3,
179162306a36Sopenharmony_ci};
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_cistatic struct davinci_mcasp_pdata dra7_mcasp_pdata = {
179462306a36Sopenharmony_ci	/* The CFG port offset will be calculated if it is needed */
179562306a36Sopenharmony_ci	.tx_dma_offset = 0,
179662306a36Sopenharmony_ci	.rx_dma_offset = 0,
179762306a36Sopenharmony_ci	.version = MCASP_VERSION_4,
179862306a36Sopenharmony_ci};
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic struct davinci_mcasp_pdata omap_mcasp_pdata = {
180162306a36Sopenharmony_ci	.tx_dma_offset = 0x200,
180262306a36Sopenharmony_ci	.rx_dma_offset = 0,
180362306a36Sopenharmony_ci	.version = MCASP_VERSION_OMAP,
180462306a36Sopenharmony_ci};
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_cistatic const struct of_device_id mcasp_dt_ids[] = {
180762306a36Sopenharmony_ci	{
180862306a36Sopenharmony_ci		.compatible = "ti,dm646x-mcasp-audio",
180962306a36Sopenharmony_ci		.data = &dm646x_mcasp_pdata,
181062306a36Sopenharmony_ci	},
181162306a36Sopenharmony_ci	{
181262306a36Sopenharmony_ci		.compatible = "ti,da830-mcasp-audio",
181362306a36Sopenharmony_ci		.data = &da830_mcasp_pdata,
181462306a36Sopenharmony_ci	},
181562306a36Sopenharmony_ci	{
181662306a36Sopenharmony_ci		.compatible = "ti,am33xx-mcasp-audio",
181762306a36Sopenharmony_ci		.data = &am33xx_mcasp_pdata,
181862306a36Sopenharmony_ci	},
181962306a36Sopenharmony_ci	{
182062306a36Sopenharmony_ci		.compatible = "ti,dra7-mcasp-audio",
182162306a36Sopenharmony_ci		.data = &dra7_mcasp_pdata,
182262306a36Sopenharmony_ci	},
182362306a36Sopenharmony_ci	{
182462306a36Sopenharmony_ci		.compatible = "ti,omap4-mcasp-audio",
182562306a36Sopenharmony_ci		.data = &omap_mcasp_pdata,
182662306a36Sopenharmony_ci	},
182762306a36Sopenharmony_ci	{ /* sentinel */ }
182862306a36Sopenharmony_ci};
182962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mcasp_dt_ids);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic int mcasp_reparent_fck(struct platform_device *pdev)
183262306a36Sopenharmony_ci{
183362306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
183462306a36Sopenharmony_ci	struct clk *gfclk, *parent_clk;
183562306a36Sopenharmony_ci	const char *parent_name;
183662306a36Sopenharmony_ci	int ret;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	if (!node)
183962306a36Sopenharmony_ci		return 0;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	parent_name = of_get_property(node, "fck_parent", NULL);
184262306a36Sopenharmony_ci	if (!parent_name)
184362306a36Sopenharmony_ci		return 0;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	gfclk = clk_get(&pdev->dev, "fck");
184862306a36Sopenharmony_ci	if (IS_ERR(gfclk)) {
184962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get fck\n");
185062306a36Sopenharmony_ci		return PTR_ERR(gfclk);
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	parent_clk = clk_get(NULL, parent_name);
185462306a36Sopenharmony_ci	if (IS_ERR(parent_clk)) {
185562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get parent clock\n");
185662306a36Sopenharmony_ci		ret = PTR_ERR(parent_clk);
185762306a36Sopenharmony_ci		goto err1;
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	ret = clk_set_parent(gfclk, parent_clk);
186162306a36Sopenharmony_ci	if (ret) {
186262306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to reparent fck\n");
186362306a36Sopenharmony_ci		goto err2;
186462306a36Sopenharmony_ci	}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_cierr2:
186762306a36Sopenharmony_ci	clk_put(parent_clk);
186862306a36Sopenharmony_cierr1:
186962306a36Sopenharmony_ci	clk_put(gfclk);
187062306a36Sopenharmony_ci	return ret;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cistatic bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp)
187462306a36Sopenharmony_ci{
187562306a36Sopenharmony_ci#ifdef CONFIG_OF_GPIO
187662306a36Sopenharmony_ci	return of_property_read_bool(mcasp->dev->of_node, "gpio-controller");
187762306a36Sopenharmony_ci#else
187862306a36Sopenharmony_ci	return false;
187962306a36Sopenharmony_ci#endif
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
188362306a36Sopenharmony_ci				    struct platform_device *pdev)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev);
188662306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
188762306a36Sopenharmony_ci	struct davinci_mcasp_pdata *pdata = NULL;
188862306a36Sopenharmony_ci	const u32 *of_serial_dir32;
188962306a36Sopenharmony_ci	u32 val;
189062306a36Sopenharmony_ci	int i;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	if (pdev->dev.platform_data) {
189362306a36Sopenharmony_ci		pdata = pdev->dev.platform_data;
189462306a36Sopenharmony_ci		pdata->dismod = DISMOD_LOW;
189562306a36Sopenharmony_ci		goto out;
189662306a36Sopenharmony_ci	} else if (match) {
189762306a36Sopenharmony_ci		pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
189862306a36Sopenharmony_ci				     GFP_KERNEL);
189962306a36Sopenharmony_ci		if (!pdata)
190062306a36Sopenharmony_ci			return -ENOMEM;
190162306a36Sopenharmony_ci	} else {
190262306a36Sopenharmony_ci		dev_err(&pdev->dev, "No compatible match found\n");
190362306a36Sopenharmony_ci		return -EINVAL;
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (of_property_read_u32(np, "op-mode", &val) == 0) {
190762306a36Sopenharmony_ci		pdata->op_mode = val;
190862306a36Sopenharmony_ci	} else {
190962306a36Sopenharmony_ci		mcasp->missing_audio_param = true;
191062306a36Sopenharmony_ci		goto out;
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
191462306a36Sopenharmony_ci		if (val < 2 || val > 32) {
191562306a36Sopenharmony_ci			dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
191662306a36Sopenharmony_ci			return -EINVAL;
191762306a36Sopenharmony_ci		}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci		pdata->tdm_slots = val;
192062306a36Sopenharmony_ci	} else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) {
192162306a36Sopenharmony_ci		mcasp->missing_audio_param = true;
192262306a36Sopenharmony_ci		goto out;
192362306a36Sopenharmony_ci	}
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	of_serial_dir32 = of_get_property(np, "serial-dir", &val);
192662306a36Sopenharmony_ci	val /= sizeof(u32);
192762306a36Sopenharmony_ci	if (of_serial_dir32) {
192862306a36Sopenharmony_ci		u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
192962306a36Sopenharmony_ci						 (sizeof(*of_serial_dir) * val),
193062306a36Sopenharmony_ci						 GFP_KERNEL);
193162306a36Sopenharmony_ci		if (!of_serial_dir)
193262306a36Sopenharmony_ci			return -ENOMEM;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		for (i = 0; i < val; i++)
193562306a36Sopenharmony_ci			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci		pdata->num_serializer = val;
193862306a36Sopenharmony_ci		pdata->serial_dir = of_serial_dir;
193962306a36Sopenharmony_ci	} else {
194062306a36Sopenharmony_ci		mcasp->missing_audio_param = true;
194162306a36Sopenharmony_ci		goto out;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
194562306a36Sopenharmony_ci		pdata->txnumevt = val;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
194862306a36Sopenharmony_ci		pdata->rxnumevt = val;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
195162306a36Sopenharmony_ci		mcasp->auxclk_fs_ratio = val;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	if (of_property_read_u32(np, "dismod", &val) == 0) {
195462306a36Sopenharmony_ci		if (val == 0 || val == 2 || val == 3) {
195562306a36Sopenharmony_ci			pdata->dismod = DISMOD_VAL(val);
195662306a36Sopenharmony_ci		} else {
195762306a36Sopenharmony_ci			dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
195862306a36Sopenharmony_ci			pdata->dismod = DISMOD_LOW;
195962306a36Sopenharmony_ci		}
196062306a36Sopenharmony_ci	} else {
196162306a36Sopenharmony_ci		pdata->dismod = DISMOD_LOW;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ciout:
196562306a36Sopenharmony_ci	mcasp->pdata = pdata;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	if (mcasp->missing_audio_param) {
196862306a36Sopenharmony_ci		if (davinci_mcasp_have_gpiochip(mcasp)) {
196962306a36Sopenharmony_ci			dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
197062306a36Sopenharmony_ci			return 0;
197162306a36Sopenharmony_ci		}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
197462306a36Sopenharmony_ci		return -ENODEV;
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	mcasp->op_mode = pdata->op_mode;
197862306a36Sopenharmony_ci	/* sanity check for tdm slots parameter */
197962306a36Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
198062306a36Sopenharmony_ci		if (pdata->tdm_slots < 2) {
198162306a36Sopenharmony_ci			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
198262306a36Sopenharmony_ci				 pdata->tdm_slots);
198362306a36Sopenharmony_ci			mcasp->tdm_slots = 2;
198462306a36Sopenharmony_ci		} else if (pdata->tdm_slots > 32) {
198562306a36Sopenharmony_ci			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
198662306a36Sopenharmony_ci				 pdata->tdm_slots);
198762306a36Sopenharmony_ci			mcasp->tdm_slots = 32;
198862306a36Sopenharmony_ci		} else {
198962306a36Sopenharmony_ci			mcasp->tdm_slots = pdata->tdm_slots;
199062306a36Sopenharmony_ci		}
199162306a36Sopenharmony_ci	} else {
199262306a36Sopenharmony_ci		mcasp->tdm_slots = 32;
199362306a36Sopenharmony_ci	}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	mcasp->num_serializer = pdata->num_serializer;
199662306a36Sopenharmony_ci#ifdef CONFIG_PM
199762306a36Sopenharmony_ci	mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
199862306a36Sopenharmony_ci						mcasp->num_serializer, sizeof(u32),
199962306a36Sopenharmony_ci						GFP_KERNEL);
200062306a36Sopenharmony_ci	if (!mcasp->context.xrsr_regs)
200162306a36Sopenharmony_ci		return -ENOMEM;
200262306a36Sopenharmony_ci#endif
200362306a36Sopenharmony_ci	mcasp->serial_dir = pdata->serial_dir;
200462306a36Sopenharmony_ci	mcasp->version = pdata->version;
200562306a36Sopenharmony_ci	mcasp->txnumevt = pdata->txnumevt;
200662306a36Sopenharmony_ci	mcasp->rxnumevt = pdata->rxnumevt;
200762306a36Sopenharmony_ci	mcasp->dismod = pdata->dismod;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	return 0;
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_cienum {
201362306a36Sopenharmony_ci	PCM_EDMA,
201462306a36Sopenharmony_ci	PCM_SDMA,
201562306a36Sopenharmony_ci	PCM_UDMA,
201662306a36Sopenharmony_ci};
201762306a36Sopenharmony_cistatic const char *sdma_prefix = "ti,omap";
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_cistatic int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	struct dma_chan *chan;
202262306a36Sopenharmony_ci	const char *tmp;
202362306a36Sopenharmony_ci	int ret = PCM_EDMA;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (!mcasp->dev->of_node)
202662306a36Sopenharmony_ci		return PCM_EDMA;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
202962306a36Sopenharmony_ci	chan = dma_request_chan(mcasp->dev, tmp);
203062306a36Sopenharmony_ci	if (IS_ERR(chan))
203162306a36Sopenharmony_ci		return dev_err_probe(mcasp->dev, PTR_ERR(chan),
203262306a36Sopenharmony_ci				     "Can't verify DMA configuration\n");
203362306a36Sopenharmony_ci	if (WARN_ON(!chan->device || !chan->device->dev)) {
203462306a36Sopenharmony_ci		dma_release_channel(chan);
203562306a36Sopenharmony_ci		return -EINVAL;
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	if (chan->device->dev->of_node)
203962306a36Sopenharmony_ci		ret = of_property_read_string(chan->device->dev->of_node,
204062306a36Sopenharmony_ci					      "compatible", &tmp);
204162306a36Sopenharmony_ci	else
204262306a36Sopenharmony_ci		dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	dma_release_channel(chan);
204562306a36Sopenharmony_ci	if (ret)
204662306a36Sopenharmony_ci		return ret;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
204962306a36Sopenharmony_ci	if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
205062306a36Sopenharmony_ci		return PCM_SDMA;
205162306a36Sopenharmony_ci	else if (strstr(tmp, "udmap"))
205262306a36Sopenharmony_ci		return PCM_UDMA;
205362306a36Sopenharmony_ci	else if (strstr(tmp, "bcdma"))
205462306a36Sopenharmony_ci		return PCM_UDMA;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	return PCM_EDMA;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	int i;
206262306a36Sopenharmony_ci	u32 offset = 0;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (pdata->version != MCASP_VERSION_4)
206562306a36Sopenharmony_ci		return pdata->tx_dma_offset;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	for (i = 0; i < pdata->num_serializer; i++) {
206862306a36Sopenharmony_ci		if (pdata->serial_dir[i] == TX_MODE) {
206962306a36Sopenharmony_ci			if (!offset) {
207062306a36Sopenharmony_ci				offset = DAVINCI_MCASP_TXBUF_REG(i);
207162306a36Sopenharmony_ci			} else {
207262306a36Sopenharmony_ci				pr_err("%s: Only one serializer allowed!\n",
207362306a36Sopenharmony_ci				       __func__);
207462306a36Sopenharmony_ci				break;
207562306a36Sopenharmony_ci			}
207662306a36Sopenharmony_ci		}
207762306a36Sopenharmony_ci	}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	return offset;
208062306a36Sopenharmony_ci}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	int i;
208562306a36Sopenharmony_ci	u32 offset = 0;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	if (pdata->version != MCASP_VERSION_4)
208862306a36Sopenharmony_ci		return pdata->rx_dma_offset;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	for (i = 0; i < pdata->num_serializer; i++) {
209162306a36Sopenharmony_ci		if (pdata->serial_dir[i] == RX_MODE) {
209262306a36Sopenharmony_ci			if (!offset) {
209362306a36Sopenharmony_ci				offset = DAVINCI_MCASP_RXBUF_REG(i);
209462306a36Sopenharmony_ci			} else {
209562306a36Sopenharmony_ci				pr_err("%s: Only one serializer allowed!\n",
209662306a36Sopenharmony_ci				       __func__);
209762306a36Sopenharmony_ci				break;
209862306a36Sopenharmony_ci			}
209962306a36Sopenharmony_ci		}
210062306a36Sopenharmony_ci	}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	return offset;
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB
210662306a36Sopenharmony_cistatic int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (mcasp->num_serializer && offset < mcasp->num_serializer &&
211162306a36Sopenharmony_ci	    mcasp->serial_dir[offset] != INACTIVE_MODE) {
211262306a36Sopenharmony_ci		dev_err(mcasp->dev, "AXR%u pin is  used for audio\n", offset);
211362306a36Sopenharmony_ci		return -EBUSY;
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/* Do not change the PIN yet */
211762306a36Sopenharmony_ci	return pm_runtime_resume_and_get(mcasp->dev);
211862306a36Sopenharmony_ci}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_cistatic void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/* Set the direction to input */
212562306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	/* Set the pin as McASP pin */
212862306a36Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	pm_runtime_put_sync(mcasp->dev);
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip,
213462306a36Sopenharmony_ci					    unsigned offset, int value)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
213762306a36Sopenharmony_ci	u32 val;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	if (value)
214062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
214162306a36Sopenharmony_ci	else
214262306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
214562306a36Sopenharmony_ci	if (!(val & BIT(offset))) {
214662306a36Sopenharmony_ci		/* Set the pin as GPIO pin */
214762306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci		/* Set the direction to output */
215062306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	return 0;
215462306a36Sopenharmony_ci}
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_cistatic void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset,
215762306a36Sopenharmony_ci				  int value)
215862306a36Sopenharmony_ci{
215962306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if (value)
216262306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
216362306a36Sopenharmony_ci	else
216462306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_cistatic int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip,
216862306a36Sopenharmony_ci					   unsigned offset)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
217162306a36Sopenharmony_ci	u32 val;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
217462306a36Sopenharmony_ci	if (!(val & BIT(offset))) {
217562306a36Sopenharmony_ci		/* Set the direction to input */
217662306a36Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		/* Set the pin as GPIO pin */
217962306a36Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
218062306a36Sopenharmony_ci	}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	return 0;
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_cistatic int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
218862306a36Sopenharmony_ci	u32 val;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG);
219162306a36Sopenharmony_ci	if (val & BIT(offset))
219262306a36Sopenharmony_ci		return 1;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return 0;
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cistatic int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip,
219862306a36Sopenharmony_ci					    unsigned offset)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
220162306a36Sopenharmony_ci	u32 val;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
220462306a36Sopenharmony_ci	if (val & BIT(offset))
220562306a36Sopenharmony_ci		return 0;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	return 1;
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic const struct gpio_chip davinci_mcasp_template_chip = {
221162306a36Sopenharmony_ci	.owner			= THIS_MODULE,
221262306a36Sopenharmony_ci	.request		= davinci_mcasp_gpio_request,
221362306a36Sopenharmony_ci	.free			= davinci_mcasp_gpio_free,
221462306a36Sopenharmony_ci	.direction_output	= davinci_mcasp_gpio_direction_out,
221562306a36Sopenharmony_ci	.set			= davinci_mcasp_gpio_set,
221662306a36Sopenharmony_ci	.direction_input	= davinci_mcasp_gpio_direction_in,
221762306a36Sopenharmony_ci	.get			= davinci_mcasp_gpio_get,
221862306a36Sopenharmony_ci	.get_direction		= davinci_mcasp_gpio_get_direction,
221962306a36Sopenharmony_ci	.base			= -1,
222062306a36Sopenharmony_ci	.ngpio			= 32,
222162306a36Sopenharmony_ci};
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_cistatic int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
222462306a36Sopenharmony_ci{
222562306a36Sopenharmony_ci	if (!davinci_mcasp_have_gpiochip(mcasp))
222662306a36Sopenharmony_ci		return 0;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	mcasp->gpio_chip = davinci_mcasp_template_chip;
222962306a36Sopenharmony_ci	mcasp->gpio_chip.label = dev_name(mcasp->dev);
223062306a36Sopenharmony_ci	mcasp->gpio_chip.parent = mcasp->dev;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp);
223362306a36Sopenharmony_ci}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci#else /* CONFIG_GPIOLIB */
223662306a36Sopenharmony_cistatic inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	return 0;
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci#endif /* CONFIG_GPIOLIB */
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cistatic int davinci_mcasp_probe(struct platform_device *pdev)
224362306a36Sopenharmony_ci{
224462306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data;
224562306a36Sopenharmony_ci	struct resource *mem, *dat;
224662306a36Sopenharmony_ci	struct davinci_mcasp *mcasp;
224762306a36Sopenharmony_ci	char *irq_name;
224862306a36Sopenharmony_ci	int irq;
224962306a36Sopenharmony_ci	int ret;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
225262306a36Sopenharmony_ci		dev_err(&pdev->dev, "No platform data supplied\n");
225362306a36Sopenharmony_ci		return -EINVAL;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
225762306a36Sopenharmony_ci			   GFP_KERNEL);
225862306a36Sopenharmony_ci	if (!mcasp)
225962306a36Sopenharmony_ci		return	-ENOMEM;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
226262306a36Sopenharmony_ci	if (!mem) {
226362306a36Sopenharmony_ci		dev_warn(&pdev->dev,
226462306a36Sopenharmony_ci			 "\"mpu\" mem resource not found, using index 0\n");
226562306a36Sopenharmony_ci		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
226662306a36Sopenharmony_ci		if (!mem) {
226762306a36Sopenharmony_ci			dev_err(&pdev->dev, "no mem resource?\n");
226862306a36Sopenharmony_ci			return -ENODEV;
226962306a36Sopenharmony_ci		}
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
227362306a36Sopenharmony_ci	if (IS_ERR(mcasp->base))
227462306a36Sopenharmony_ci		return PTR_ERR(mcasp->base);
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, mcasp);
227762306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	mcasp->dev = &pdev->dev;
228062306a36Sopenharmony_ci	ret = davinci_mcasp_get_config(mcasp, pdev);
228162306a36Sopenharmony_ci	if (ret)
228262306a36Sopenharmony_ci		goto err;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/* All PINS as McASP */
228562306a36Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
228662306a36Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
228762306a36Sopenharmony_ci	pm_runtime_put(mcasp->dev);
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	/* Skip audio related setup code if the configuration is not adequat */
229062306a36Sopenharmony_ci	if (mcasp->missing_audio_param)
229162306a36Sopenharmony_ci		goto no_audio;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	irq = platform_get_irq_byname_optional(pdev, "common");
229462306a36Sopenharmony_ci	if (irq > 0) {
229562306a36Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
229662306a36Sopenharmony_ci					  dev_name(&pdev->dev));
229762306a36Sopenharmony_ci		if (!irq_name) {
229862306a36Sopenharmony_ci			ret = -ENOMEM;
229962306a36Sopenharmony_ci			goto err;
230062306a36Sopenharmony_ci		}
230162306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
230262306a36Sopenharmony_ci						davinci_mcasp_common_irq_handler,
230362306a36Sopenharmony_ci						IRQF_ONESHOT | IRQF_SHARED,
230462306a36Sopenharmony_ci						irq_name, mcasp);
230562306a36Sopenharmony_ci		if (ret) {
230662306a36Sopenharmony_ci			dev_err(&pdev->dev, "common IRQ request failed\n");
230762306a36Sopenharmony_ci			goto err;
230862306a36Sopenharmony_ci		}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
231162306a36Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	irq = platform_get_irq_byname_optional(pdev, "rx");
231562306a36Sopenharmony_ci	if (irq > 0) {
231662306a36Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
231762306a36Sopenharmony_ci					  dev_name(&pdev->dev));
231862306a36Sopenharmony_ci		if (!irq_name) {
231962306a36Sopenharmony_ci			ret = -ENOMEM;
232062306a36Sopenharmony_ci			goto err;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
232362306a36Sopenharmony_ci						davinci_mcasp_rx_irq_handler,
232462306a36Sopenharmony_ci						IRQF_ONESHOT, irq_name, mcasp);
232562306a36Sopenharmony_ci		if (ret) {
232662306a36Sopenharmony_ci			dev_err(&pdev->dev, "RX IRQ request failed\n");
232762306a36Sopenharmony_ci			goto err;
232862306a36Sopenharmony_ci		}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	irq = platform_get_irq_byname_optional(pdev, "tx");
233462306a36Sopenharmony_ci	if (irq > 0) {
233562306a36Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
233662306a36Sopenharmony_ci					  dev_name(&pdev->dev));
233762306a36Sopenharmony_ci		if (!irq_name) {
233862306a36Sopenharmony_ci			ret = -ENOMEM;
233962306a36Sopenharmony_ci			goto err;
234062306a36Sopenharmony_ci		}
234162306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
234262306a36Sopenharmony_ci						davinci_mcasp_tx_irq_handler,
234362306a36Sopenharmony_ci						IRQF_ONESHOT, irq_name, mcasp);
234462306a36Sopenharmony_ci		if (ret) {
234562306a36Sopenharmony_ci			dev_err(&pdev->dev, "TX IRQ request failed\n");
234662306a36Sopenharmony_ci			goto err;
234762306a36Sopenharmony_ci		}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
235062306a36Sopenharmony_ci	}
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
235362306a36Sopenharmony_ci	if (dat)
235462306a36Sopenharmony_ci		mcasp->dat_port = true;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
235762306a36Sopenharmony_ci	dma_data->filter_data = "tx";
235862306a36Sopenharmony_ci	if (dat) {
235962306a36Sopenharmony_ci		dma_data->addr = dat->start;
236062306a36Sopenharmony_ci		/*
236162306a36Sopenharmony_ci		 * According to the TRM there should be 0x200 offset added to
236262306a36Sopenharmony_ci		 * the DAT port address
236362306a36Sopenharmony_ci		 */
236462306a36Sopenharmony_ci		if (mcasp->version == MCASP_VERSION_OMAP)
236562306a36Sopenharmony_ci			dma_data->addr += davinci_mcasp_txdma_offset(mcasp->pdata);
236662306a36Sopenharmony_ci	} else {
236762306a36Sopenharmony_ci		dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/* RX is not valid in DIT mode */
237262306a36Sopenharmony_ci	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
237362306a36Sopenharmony_ci		dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
237462306a36Sopenharmony_ci		dma_data->filter_data = "rx";
237562306a36Sopenharmony_ci		if (dat)
237662306a36Sopenharmony_ci			dma_data->addr = dat->start;
237762306a36Sopenharmony_ci		else
237862306a36Sopenharmony_ci			dma_data->addr =
237962306a36Sopenharmony_ci				mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
238062306a36Sopenharmony_ci	}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	if (mcasp->version < MCASP_VERSION_3) {
238362306a36Sopenharmony_ci		mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
238462306a36Sopenharmony_ci		/* dma_params->dma_addr is pointing to the data port address */
238562306a36Sopenharmony_ci		mcasp->dat_port = true;
238662306a36Sopenharmony_ci	} else {
238762306a36Sopenharmony_ci		mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
238862306a36Sopenharmony_ci	}
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	/* Allocate memory for long enough list for all possible
239162306a36Sopenharmony_ci	 * scenarios. Maximum number tdm slots is 32 and there cannot
239262306a36Sopenharmony_ci	 * be more serializers than given in the configuration.  The
239362306a36Sopenharmony_ci	 * serializer directions could be taken into account, but it
239462306a36Sopenharmony_ci	 * would make code much more complex and save only couple of
239562306a36Sopenharmony_ci	 * bytes.
239662306a36Sopenharmony_ci	 */
239762306a36Sopenharmony_ci	mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
239862306a36Sopenharmony_ci		devm_kcalloc(mcasp->dev,
239962306a36Sopenharmony_ci			     32 + mcasp->num_serializer - 1,
240062306a36Sopenharmony_ci			     sizeof(unsigned int),
240162306a36Sopenharmony_ci			     GFP_KERNEL);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
240462306a36Sopenharmony_ci		devm_kcalloc(mcasp->dev,
240562306a36Sopenharmony_ci			     32 + mcasp->num_serializer - 1,
240662306a36Sopenharmony_ci			     sizeof(unsigned int),
240762306a36Sopenharmony_ci			     GFP_KERNEL);
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
241062306a36Sopenharmony_ci	    !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
241162306a36Sopenharmony_ci		ret = -ENOMEM;
241262306a36Sopenharmony_ci		goto err;
241362306a36Sopenharmony_ci	}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	ret = davinci_mcasp_set_ch_constraints(mcasp);
241662306a36Sopenharmony_ci	if (ret)
241762306a36Sopenharmony_ci		goto err;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	mcasp_reparent_fck(pdev);
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
242262306a36Sopenharmony_ci					      &davinci_mcasp_dai[mcasp->op_mode], 1);
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	if (ret != 0)
242562306a36Sopenharmony_ci		goto err;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	ret = davinci_mcasp_get_dma_type(mcasp);
242862306a36Sopenharmony_ci	switch (ret) {
242962306a36Sopenharmony_ci	case PCM_EDMA:
243062306a36Sopenharmony_ci		ret = edma_pcm_platform_register(&pdev->dev);
243162306a36Sopenharmony_ci		break;
243262306a36Sopenharmony_ci	case PCM_SDMA:
243362306a36Sopenharmony_ci		if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
243462306a36Sopenharmony_ci			ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
243562306a36Sopenharmony_ci		else
243662306a36Sopenharmony_ci			ret = sdma_pcm_platform_register(&pdev->dev, "tx", NULL);
243762306a36Sopenharmony_ci		break;
243862306a36Sopenharmony_ci	case PCM_UDMA:
243962306a36Sopenharmony_ci		ret = udma_pcm_platform_register(&pdev->dev);
244062306a36Sopenharmony_ci		break;
244162306a36Sopenharmony_ci	default:
244262306a36Sopenharmony_ci		dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
244362306a36Sopenharmony_ci		fallthrough;
244462306a36Sopenharmony_ci	case -EPROBE_DEFER:
244562306a36Sopenharmony_ci		goto err;
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	if (ret) {
244962306a36Sopenharmony_ci		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
245062306a36Sopenharmony_ci		goto err;
245162306a36Sopenharmony_ci	}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cino_audio:
245462306a36Sopenharmony_ci	ret = davinci_mcasp_init_gpiochip(mcasp);
245562306a36Sopenharmony_ci	if (ret) {
245662306a36Sopenharmony_ci		dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret);
245762306a36Sopenharmony_ci		goto err;
245862306a36Sopenharmony_ci	}
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	return 0;
246162306a36Sopenharmony_cierr:
246262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
246362306a36Sopenharmony_ci	return ret;
246462306a36Sopenharmony_ci}
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_cistatic void davinci_mcasp_remove(struct platform_device *pdev)
246762306a36Sopenharmony_ci{
246862306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci#ifdef CONFIG_PM
247262306a36Sopenharmony_cistatic int davinci_mcasp_runtime_suspend(struct device *dev)
247362306a36Sopenharmony_ci{
247462306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
247562306a36Sopenharmony_ci	struct davinci_mcasp_context *context = &mcasp->context;
247662306a36Sopenharmony_ci	u32 reg;
247762306a36Sopenharmony_ci	int i;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
248062306a36Sopenharmony_ci		context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if (mcasp->txnumevt) {
248362306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
248462306a36Sopenharmony_ci		context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci	if (mcasp->rxnumevt) {
248762306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
248862306a36Sopenharmony_ci		context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
248962306a36Sopenharmony_ci	}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
249262306a36Sopenharmony_ci		context->xrsr_regs[i] = mcasp_get_reg(mcasp,
249362306a36Sopenharmony_ci						DAVINCI_MCASP_XRSRCTL_REG(i));
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	return 0;
249662306a36Sopenharmony_ci}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_cistatic int davinci_mcasp_runtime_resume(struct device *dev)
249962306a36Sopenharmony_ci{
250062306a36Sopenharmony_ci	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
250162306a36Sopenharmony_ci	struct davinci_mcasp_context *context = &mcasp->context;
250262306a36Sopenharmony_ci	u32 reg;
250362306a36Sopenharmony_ci	int i;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
250662306a36Sopenharmony_ci		mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	if (mcasp->txnumevt) {
250962306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
251062306a36Sopenharmony_ci		mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
251162306a36Sopenharmony_ci	}
251262306a36Sopenharmony_ci	if (mcasp->rxnumevt) {
251362306a36Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
251462306a36Sopenharmony_ci		mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
251862306a36Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
251962306a36Sopenharmony_ci			      context->xrsr_regs[i]);
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	return 0;
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci#endif
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_cistatic const struct dev_pm_ops davinci_mcasp_pm_ops = {
252762306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
252862306a36Sopenharmony_ci			   davinci_mcasp_runtime_resume,
252962306a36Sopenharmony_ci			   NULL)
253062306a36Sopenharmony_ci};
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_cistatic struct platform_driver davinci_mcasp_driver = {
253362306a36Sopenharmony_ci	.probe		= davinci_mcasp_probe,
253462306a36Sopenharmony_ci	.remove_new	= davinci_mcasp_remove,
253562306a36Sopenharmony_ci	.driver		= {
253662306a36Sopenharmony_ci		.name	= "davinci-mcasp",
253762306a36Sopenharmony_ci		.pm     = &davinci_mcasp_pm_ops,
253862306a36Sopenharmony_ci		.of_match_table = mcasp_dt_ids,
253962306a36Sopenharmony_ci	},
254062306a36Sopenharmony_ci};
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_cimodule_platform_driver(davinci_mcasp_driver);
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ciMODULE_AUTHOR("Steve Chen");
254562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
254662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2547