18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ALSA SoC McASP Audio Layer for TI DAVINCI processor
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Multi-channel Audio Serial Port Driver
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Nirmal Pandey <n-pandey@ti.com>,
88c2ecf20Sopenharmony_ci *         Suresh Rajashekara <suresh.r@ti.com>
98c2ecf20Sopenharmony_ci *         Steve Chen <schen@.mvista.com>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
128c2ecf20Sopenharmony_ci * Copyright:   (C) 2009  Texas Instruments, India
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/device.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/delay.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/clk.h>
228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
238c2ecf20Sopenharmony_ci#include <linux/of.h>
248c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
258c2ecf20Sopenharmony_ci#include <linux/of_device.h>
268c2ecf20Sopenharmony_ci#include <linux/platform_data/davinci_asp.h>
278c2ecf20Sopenharmony_ci#include <linux/math64.h>
288c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
298c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <sound/asoundef.h>
328c2ecf20Sopenharmony_ci#include <sound/core.h>
338c2ecf20Sopenharmony_ci#include <sound/pcm.h>
348c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
358c2ecf20Sopenharmony_ci#include <sound/initval.h>
368c2ecf20Sopenharmony_ci#include <sound/soc.h>
378c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "edma-pcm.h"
408c2ecf20Sopenharmony_ci#include "sdma-pcm.h"
418c2ecf20Sopenharmony_ci#include "udma-pcm.h"
428c2ecf20Sopenharmony_ci#include "davinci-mcasp.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define MCASP_MAX_AFIFO_DEPTH	64
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
478c2ecf20Sopenharmony_cistatic u32 context_regs[] = {
488c2ecf20Sopenharmony_ci	DAVINCI_MCASP_TXFMCTL_REG,
498c2ecf20Sopenharmony_ci	DAVINCI_MCASP_RXFMCTL_REG,
508c2ecf20Sopenharmony_ci	DAVINCI_MCASP_TXFMT_REG,
518c2ecf20Sopenharmony_ci	DAVINCI_MCASP_RXFMT_REG,
528c2ecf20Sopenharmony_ci	DAVINCI_MCASP_ACLKXCTL_REG,
538c2ecf20Sopenharmony_ci	DAVINCI_MCASP_ACLKRCTL_REG,
548c2ecf20Sopenharmony_ci	DAVINCI_MCASP_AHCLKXCTL_REG,
558c2ecf20Sopenharmony_ci	DAVINCI_MCASP_AHCLKRCTL_REG,
568c2ecf20Sopenharmony_ci	DAVINCI_MCASP_PDIR_REG,
578c2ecf20Sopenharmony_ci	DAVINCI_MCASP_PFUNC_REG,
588c2ecf20Sopenharmony_ci	DAVINCI_MCASP_RXMASK_REG,
598c2ecf20Sopenharmony_ci	DAVINCI_MCASP_TXMASK_REG,
608c2ecf20Sopenharmony_ci	DAVINCI_MCASP_RXTDM_REG,
618c2ecf20Sopenharmony_ci	DAVINCI_MCASP_TXTDM_REG,
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct davinci_mcasp_context {
658c2ecf20Sopenharmony_ci	u32	config_regs[ARRAY_SIZE(context_regs)];
668c2ecf20Sopenharmony_ci	u32	afifo_regs[2]; /* for read/write fifo control registers */
678c2ecf20Sopenharmony_ci	u32	*xrsr_regs; /* for serializer configuration */
688c2ecf20Sopenharmony_ci	bool	pm_state;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci#endif
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistruct davinci_mcasp_ruledata {
738c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp;
748c2ecf20Sopenharmony_ci	int serializers;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct davinci_mcasp {
788c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data dma_data[2];
798c2ecf20Sopenharmony_ci	void __iomem *base;
808c2ecf20Sopenharmony_ci	u32 fifo_base;
818c2ecf20Sopenharmony_ci	struct device *dev;
828c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substreams[2];
838c2ecf20Sopenharmony_ci	unsigned int dai_fmt;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* McASP specific data */
868c2ecf20Sopenharmony_ci	int	tdm_slots;
878c2ecf20Sopenharmony_ci	u32	tdm_mask[2];
888c2ecf20Sopenharmony_ci	int	slot_width;
898c2ecf20Sopenharmony_ci	u8	op_mode;
908c2ecf20Sopenharmony_ci	u8	dismod;
918c2ecf20Sopenharmony_ci	u8	num_serializer;
928c2ecf20Sopenharmony_ci	u8	*serial_dir;
938c2ecf20Sopenharmony_ci	u8	version;
948c2ecf20Sopenharmony_ci	u8	bclk_div;
958c2ecf20Sopenharmony_ci	int	streams;
968c2ecf20Sopenharmony_ci	u32	irq_request[2];
978c2ecf20Sopenharmony_ci	int	dma_request[2];
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	int	sysclk_freq;
1008c2ecf20Sopenharmony_ci	bool	bclk_master;
1018c2ecf20Sopenharmony_ci	u32	auxclk_fs_ratio;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	unsigned long pdir; /* Pin direction bitfield */
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* McASP FIFO related */
1068c2ecf20Sopenharmony_ci	u8	txnumevt;
1078c2ecf20Sopenharmony_ci	u8	rxnumevt;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	bool	dat_port;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Used for comstraint setting on the second stream */
1128c2ecf20Sopenharmony_ci	u32	channels;
1138c2ecf20Sopenharmony_ci	int	max_format_width;
1148c2ecf20Sopenharmony_ci	u8	active_serializers[2];
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB
1178c2ecf20Sopenharmony_ci	struct gpio_chip gpio_chip;
1188c2ecf20Sopenharmony_ci#endif
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1218c2ecf20Sopenharmony_ci	struct davinci_mcasp_context context;
1228c2ecf20Sopenharmony_ci#endif
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata ruledata[2];
1258c2ecf20Sopenharmony_ci	struct snd_pcm_hw_constraint_list chconstr[2];
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
1298c2ecf20Sopenharmony_ci				  u32 val)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
1328c2ecf20Sopenharmony_ci	__raw_writel(__raw_readl(reg) | val, reg);
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
1368c2ecf20Sopenharmony_ci				  u32 val)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
1398c2ecf20Sopenharmony_ci	__raw_writel((__raw_readl(reg) & ~(val)), reg);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
1438c2ecf20Sopenharmony_ci				  u32 val, u32 mask)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	void __iomem *reg = mcasp->base + offset;
1468c2ecf20Sopenharmony_ci	__raw_writel((__raw_readl(reg) & ~mask) | val, reg);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
1508c2ecf20Sopenharmony_ci				 u32 val)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	__raw_writel(val, mcasp->base + offset);
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	return (u32)__raw_readl(mcasp->base + offset);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	int i = 0;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, ctl_reg, val);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* programming GBLCTL needs to read back from GBLCTL and verfiy */
1678c2ecf20Sopenharmony_ci	/* loop count is to avoid the lock-up */
1688c2ecf20Sopenharmony_ci	for (i = 0; i < 1000; i++) {
1698c2ecf20Sopenharmony_ci		if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
1708c2ecf20Sopenharmony_ci			break;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
1748c2ecf20Sopenharmony_ci		printk(KERN_ERR "GBLCTL write error\n");
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
1808c2ecf20Sopenharmony_ci	u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	u32 bit = PIN_BIT_AMUTE;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
1908c2ecf20Sopenharmony_ci		if (enable)
1918c2ecf20Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
1928c2ecf20Sopenharmony_ci		else
1938c2ecf20Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	u32 bit;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) {
2028c2ecf20Sopenharmony_ci		if (enable)
2038c2ecf20Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
2048c2ecf20Sopenharmony_ci		else
2058c2ecf20Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void mcasp_start_rx(struct davinci_mcasp *mcasp)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	if (mcasp->rxnumevt) {	/* enable FIFO */
2128c2ecf20Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
2158c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Start clocks */
2198c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
2208c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * When ASYNC == 0 the transmit and receive sections operate
2238c2ecf20Sopenharmony_ci	 * synchronously from the transmit clock and frame sync. We need to make
2248c2ecf20Sopenharmony_ci	 * sure that the TX signlas are enabled when starting reception.
2258c2ecf20Sopenharmony_ci	 */
2268c2ecf20Sopenharmony_ci	if (mcasp_is_synchronous(mcasp)) {
2278c2ecf20Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
2288c2ecf20Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
2298c2ecf20Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, true);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Activate serializer(s) */
2338c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
2348c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
2358c2ecf20Sopenharmony_ci	/* Release RX state machine */
2368c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
2378c2ecf20Sopenharmony_ci	/* Release Frame Sync generator */
2388c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
2398c2ecf20Sopenharmony_ci	if (mcasp_is_synchronous(mcasp))
2408c2ecf20Sopenharmony_ci		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* enable receive IRQs */
2438c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
2448c2ecf20Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic void mcasp_start_tx(struct davinci_mcasp *mcasp)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	u32 cnt;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (mcasp->txnumevt) {	/* enable FIFO */
2528c2ecf20Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
2558c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	/* Start clocks */
2598c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
2608c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
2618c2ecf20Sopenharmony_ci	mcasp_set_clk_pdir(mcasp, true);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Activate serializer(s) */
2648c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
2658c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* wait for XDATA to be cleared */
2688c2ecf20Sopenharmony_ci	cnt = 0;
2698c2ecf20Sopenharmony_ci	while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
2708c2ecf20Sopenharmony_ci	       (cnt < 100000))
2718c2ecf20Sopenharmony_ci		cnt++;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	mcasp_set_axr_pdir(mcasp, true);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* Release TX state machine */
2768c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
2778c2ecf20Sopenharmony_ci	/* Release Frame Sync generator */
2788c2ecf20Sopenharmony_ci	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* enable transmit IRQs */
2818c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
2828c2ecf20Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	mcasp->streams++;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
2908c2ecf20Sopenharmony_ci		mcasp_start_tx(mcasp);
2918c2ecf20Sopenharmony_ci	else
2928c2ecf20Sopenharmony_ci		mcasp_start_rx(mcasp);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void mcasp_stop_rx(struct davinci_mcasp *mcasp)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	/* disable IRQ sources */
2988c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
2998c2ecf20Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/*
3028c2ecf20Sopenharmony_ci	 * In synchronous mode stop the TX clocks if no other stream is
3038c2ecf20Sopenharmony_ci	 * running
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
3068c2ecf20Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, false);
3078c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
3118c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (mcasp->rxnumevt) {	/* disable FIFO */
3148c2ecf20Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void mcasp_stop_tx(struct davinci_mcasp *mcasp)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u32 val = 0;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* disable IRQ sources */
3258c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
3268c2ecf20Sopenharmony_ci		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/*
3298c2ecf20Sopenharmony_ci	 * In synchronous mode keep TX clocks running if the capture stream is
3308c2ecf20Sopenharmony_ci	 * still running.
3318c2ecf20Sopenharmony_ci	 */
3328c2ecf20Sopenharmony_ci	if (mcasp_is_synchronous(mcasp) && mcasp->streams)
3338c2ecf20Sopenharmony_ci		val =  TXHCLKRST | TXCLKRST | TXFSRST;
3348c2ecf20Sopenharmony_ci	else
3358c2ecf20Sopenharmony_ci		mcasp_set_clk_pdir(mcasp, false);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
3398c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (mcasp->txnumevt) {	/* disable FIFO */
3428c2ecf20Sopenharmony_ci		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	mcasp_set_axr_pdir(mcasp, false);
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	mcasp->streams--;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3558c2ecf20Sopenharmony_ci		mcasp_stop_tx(mcasp);
3568c2ecf20Sopenharmony_ci	else
3578c2ecf20Sopenharmony_ci		mcasp_stop_rx(mcasp);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
3638c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
3648c2ecf20Sopenharmony_ci	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
3658c2ecf20Sopenharmony_ci	u32 handled_mask = 0;
3668c2ecf20Sopenharmony_ci	u32 stat;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
3698c2ecf20Sopenharmony_ci	if (stat & XUNDRN & irq_mask) {
3708c2ecf20Sopenharmony_ci		dev_warn(mcasp->dev, "Transmit buffer underflow\n");
3718c2ecf20Sopenharmony_ci		handled_mask |= XUNDRN;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
3748c2ecf20Sopenharmony_ci		if (substream)
3758c2ecf20Sopenharmony_ci			snd_pcm_stop_xrun(substream);
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (!handled_mask)
3798c2ecf20Sopenharmony_ci		dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
3808c2ecf20Sopenharmony_ci			 stat);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (stat & XRERR)
3838c2ecf20Sopenharmony_ci		handled_mask |= XRERR;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* Ack the handled event only */
3868c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled_mask);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
3948c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
3958c2ecf20Sopenharmony_ci	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
3968c2ecf20Sopenharmony_ci	u32 handled_mask = 0;
3978c2ecf20Sopenharmony_ci	u32 stat;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
4008c2ecf20Sopenharmony_ci	if (stat & ROVRN & irq_mask) {
4018c2ecf20Sopenharmony_ci		dev_warn(mcasp->dev, "Receive buffer overflow\n");
4028c2ecf20Sopenharmony_ci		handled_mask |= ROVRN;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
4058c2ecf20Sopenharmony_ci		if (substream)
4068c2ecf20Sopenharmony_ci			snd_pcm_stop_xrun(substream);
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (!handled_mask)
4108c2ecf20Sopenharmony_ci		dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
4118c2ecf20Sopenharmony_ci			 stat);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (stat & XRERR)
4148c2ecf20Sopenharmony_ci		handled_mask |= XRERR;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	/* Ack the handled event only */
4178c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled_mask);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
4258c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
4288c2ecf20Sopenharmony_ci		ret = davinci_mcasp_tx_irq_handler(irq, data);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
4318c2ecf20Sopenharmony_ci		ret |= davinci_mcasp_rx_irq_handler(irq, data);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return ret;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
4378c2ecf20Sopenharmony_ci					 unsigned int fmt)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
4408c2ecf20Sopenharmony_ci	int ret = 0;
4418c2ecf20Sopenharmony_ci	u32 data_delay;
4428c2ecf20Sopenharmony_ci	bool fs_pol_rising;
4438c2ecf20Sopenharmony_ci	bool inv_fs = false;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (!fmt)
4468c2ecf20Sopenharmony_ci		return 0;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
4498c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
4508c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
4518c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
4528c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4538c2ecf20Sopenharmony_ci		/* 1st data bit occur one ACLK cycle after the frame sync */
4548c2ecf20Sopenharmony_ci		data_delay = 1;
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B:
4578c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_AC97:
4588c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
4598c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4608c2ecf20Sopenharmony_ci		/* No delay after FS */
4618c2ecf20Sopenharmony_ci		data_delay = 0;
4628c2ecf20Sopenharmony_ci		break;
4638c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
4648c2ecf20Sopenharmony_ci		/* configure a full-word SYNC pulse (LRCLK) */
4658c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
4668c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4678c2ecf20Sopenharmony_ci		/* 1st data bit occur one ACLK cycle after the frame sync */
4688c2ecf20Sopenharmony_ci		data_delay = 1;
4698c2ecf20Sopenharmony_ci		/* FS need to be inverted */
4708c2ecf20Sopenharmony_ci		inv_fs = true;
4718c2ecf20Sopenharmony_ci		break;
4728c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
4738c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
4748c2ecf20Sopenharmony_ci		/* configure a full-word SYNC pulse (LRCLK) */
4758c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
4768c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4778c2ecf20Sopenharmony_ci		/* No delay after FS */
4788c2ecf20Sopenharmony_ci		data_delay = 0;
4798c2ecf20Sopenharmony_ci		break;
4808c2ecf20Sopenharmony_ci	default:
4818c2ecf20Sopenharmony_ci		ret = -EINVAL;
4828c2ecf20Sopenharmony_ci		goto out;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
4868c2ecf20Sopenharmony_ci		       FSXDLY(3));
4878c2ecf20Sopenharmony_ci	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
4888c2ecf20Sopenharmony_ci		       FSRDLY(3));
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
4918c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
4928c2ecf20Sopenharmony_ci		/* codec is clock and frame slave */
4938c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
4948c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
4978c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		/* BCLK */
5008c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
5018c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
5028c2ecf20Sopenharmony_ci		/* Frame Sync */
5038c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
5048c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		mcasp->bclk_master = 1;
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFM:
5098c2ecf20Sopenharmony_ci		/* codec is clock slave and frame master */
5108c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
5118c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
5148c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		/* BCLK */
5178c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
5188c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
5198c2ecf20Sopenharmony_ci		/* Frame Sync */
5208c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
5218c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		mcasp->bclk_master = 1;
5248c2ecf20Sopenharmony_ci		break;
5258c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFS:
5268c2ecf20Sopenharmony_ci		/* codec is clock master and frame slave */
5278c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
5288c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
5318c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		/* BCLK */
5348c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
5358c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
5368c2ecf20Sopenharmony_ci		/* Frame Sync */
5378c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
5388c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		mcasp->bclk_master = 0;
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
5438c2ecf20Sopenharmony_ci		/* codec is clock and frame master */
5448c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
5458c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
5488c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		/* BCLK */
5518c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
5528c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
5538c2ecf20Sopenharmony_ci		/* Frame Sync */
5548c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
5558c2ecf20Sopenharmony_ci		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		mcasp->bclk_master = 0;
5588c2ecf20Sopenharmony_ci		break;
5598c2ecf20Sopenharmony_ci	default:
5608c2ecf20Sopenharmony_ci		ret = -EINVAL;
5618c2ecf20Sopenharmony_ci		goto out;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
5658c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF:
5668c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
5678c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
5688c2ecf20Sopenharmony_ci		fs_pol_rising = true;
5698c2ecf20Sopenharmony_ci		break;
5708c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_IF:
5718c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
5728c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
5738c2ecf20Sopenharmony_ci		fs_pol_rising = false;
5748c2ecf20Sopenharmony_ci		break;
5758c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_IB_IF:
5768c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
5778c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
5788c2ecf20Sopenharmony_ci		fs_pol_rising = false;
5798c2ecf20Sopenharmony_ci		break;
5808c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
5818c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
5828c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
5838c2ecf20Sopenharmony_ci		fs_pol_rising = true;
5848c2ecf20Sopenharmony_ci		break;
5858c2ecf20Sopenharmony_ci	default:
5868c2ecf20Sopenharmony_ci		ret = -EINVAL;
5878c2ecf20Sopenharmony_ci		goto out;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (inv_fs)
5918c2ecf20Sopenharmony_ci		fs_pol_rising = !fs_pol_rising;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	if (fs_pol_rising) {
5948c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
5958c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
5968c2ecf20Sopenharmony_ci	} else {
5978c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
5988c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	mcasp->dai_fmt = fmt;
6028c2ecf20Sopenharmony_ciout:
6038c2ecf20Sopenharmony_ci	pm_runtime_put(mcasp->dev);
6048c2ecf20Sopenharmony_ci	return ret;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
6088c2ecf20Sopenharmony_ci				      int div, bool explicit)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
6118c2ecf20Sopenharmony_ci	switch (div_id) {
6128c2ecf20Sopenharmony_ci	case MCASP_CLKDIV_AUXCLK:			/* MCLK divider */
6138c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
6148c2ecf20Sopenharmony_ci			       AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
6158c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
6168c2ecf20Sopenharmony_ci			       AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
6178c2ecf20Sopenharmony_ci		break;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	case MCASP_CLKDIV_BCLK:			/* BCLK divider */
6208c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
6218c2ecf20Sopenharmony_ci			       ACLKXDIV(div - 1), ACLKXDIV_MASK);
6228c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
6238c2ecf20Sopenharmony_ci			       ACLKRDIV(div - 1), ACLKRDIV_MASK);
6248c2ecf20Sopenharmony_ci		if (explicit)
6258c2ecf20Sopenharmony_ci			mcasp->bclk_div = div;
6268c2ecf20Sopenharmony_ci		break;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	case MCASP_CLKDIV_BCLK_FS_RATIO:
6298c2ecf20Sopenharmony_ci		/*
6308c2ecf20Sopenharmony_ci		 * BCLK/LRCLK ratio descries how many bit-clock cycles
6318c2ecf20Sopenharmony_ci		 * fit into one frame. The clock ratio is given for a
6328c2ecf20Sopenharmony_ci		 * full period of data (for I2S format both left and
6338c2ecf20Sopenharmony_ci		 * right channels), so it has to be divided by number
6348c2ecf20Sopenharmony_ci		 * of tdm-slots (for I2S - divided by 2).
6358c2ecf20Sopenharmony_ci		 * Instead of storing this ratio, we calculate a new
6368c2ecf20Sopenharmony_ci		 * tdm_slot width by dividing the ratio by the
6378c2ecf20Sopenharmony_ci		 * number of configured tdm slots.
6388c2ecf20Sopenharmony_ci		 */
6398c2ecf20Sopenharmony_ci		mcasp->slot_width = div / mcasp->tdm_slots;
6408c2ecf20Sopenharmony_ci		if (div % mcasp->tdm_slots)
6418c2ecf20Sopenharmony_ci			dev_warn(mcasp->dev,
6428c2ecf20Sopenharmony_ci				 "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
6438c2ecf20Sopenharmony_ci				 __func__, div, mcasp->tdm_slots);
6448c2ecf20Sopenharmony_ci		break;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	default:
6478c2ecf20Sopenharmony_ci		return -EINVAL;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	pm_runtime_put(mcasp->dev);
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
6558c2ecf20Sopenharmony_ci				    int div)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
6638c2ecf20Sopenharmony_ci				    unsigned int freq, int dir)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (dir == SND_SOC_CLOCK_IN) {
6708c2ecf20Sopenharmony_ci		switch (clk_id) {
6718c2ecf20Sopenharmony_ci		case MCASP_CLK_HCLK_AHCLK:
6728c2ecf20Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
6738c2ecf20Sopenharmony_ci				       AHCLKXE);
6748c2ecf20Sopenharmony_ci			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
6758c2ecf20Sopenharmony_ci				       AHCLKRE);
6768c2ecf20Sopenharmony_ci			clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
6778c2ecf20Sopenharmony_ci			break;
6788c2ecf20Sopenharmony_ci		case MCASP_CLK_HCLK_AUXCLK:
6798c2ecf20Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
6808c2ecf20Sopenharmony_ci				       AHCLKXE);
6818c2ecf20Sopenharmony_ci			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
6828c2ecf20Sopenharmony_ci				       AHCLKRE);
6838c2ecf20Sopenharmony_ci			set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
6848c2ecf20Sopenharmony_ci			break;
6858c2ecf20Sopenharmony_ci		default:
6868c2ecf20Sopenharmony_ci			dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id);
6878c2ecf20Sopenharmony_ci			goto out;
6888c2ecf20Sopenharmony_ci		}
6898c2ecf20Sopenharmony_ci	} else {
6908c2ecf20Sopenharmony_ci		/* Select AUXCLK as HCLK */
6918c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
6928c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
6938c2ecf20Sopenharmony_ci		set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci	/*
6968c2ecf20Sopenharmony_ci	 * When AHCLK X/R is selected to be output it means that the HCLK is
6978c2ecf20Sopenharmony_ci	 * the same clock - coming via AUXCLK.
6988c2ecf20Sopenharmony_ci	 */
6998c2ecf20Sopenharmony_ci	mcasp->sysclk_freq = freq;
7008c2ecf20Sopenharmony_ciout:
7018c2ecf20Sopenharmony_ci	pm_runtime_put(mcasp->dev);
7028c2ecf20Sopenharmony_ci	return 0;
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci/* All serializers must have equal number of channels */
7068c2ecf20Sopenharmony_cistatic int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
7078c2ecf20Sopenharmony_ci				       int serializers)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
7108c2ecf20Sopenharmony_ci	unsigned int *list = (unsigned int *) cl->list;
7118c2ecf20Sopenharmony_ci	int slots = mcasp->tdm_slots;
7128c2ecf20Sopenharmony_ci	int i, count = 0;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (mcasp->tdm_mask[stream])
7158c2ecf20Sopenharmony_ci		slots = hweight32(mcasp->tdm_mask[stream]);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	for (i = 1; i <= slots; i++)
7188c2ecf20Sopenharmony_ci		list[count++] = i;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	for (i = 2; i <= serializers; i++)
7218c2ecf20Sopenharmony_ci		list[count++] = i*slots;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	cl->count = count;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	return 0;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	int rx_serializers = 0, tx_serializers = 0, ret, i;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
7338c2ecf20Sopenharmony_ci		if (mcasp->serial_dir[i] == TX_MODE)
7348c2ecf20Sopenharmony_ci			tx_serializers++;
7358c2ecf20Sopenharmony_ci		else if (mcasp->serial_dir[i] == RX_MODE)
7368c2ecf20Sopenharmony_ci			rx_serializers++;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
7398c2ecf20Sopenharmony_ci					  tx_serializers);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		return ret;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
7448c2ecf20Sopenharmony_ci					  rx_serializers);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return ret;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
7518c2ecf20Sopenharmony_ci				      unsigned int tx_mask,
7528c2ecf20Sopenharmony_ci				      unsigned int rx_mask,
7538c2ecf20Sopenharmony_ci				      int slots, int slot_width)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	dev_dbg(mcasp->dev,
7588c2ecf20Sopenharmony_ci		 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
7598c2ecf20Sopenharmony_ci		 __func__, tx_mask, rx_mask, slots, slot_width);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
7628c2ecf20Sopenharmony_ci		dev_err(mcasp->dev,
7638c2ecf20Sopenharmony_ci			"Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
7648c2ecf20Sopenharmony_ci			tx_mask, rx_mask, slots);
7658c2ecf20Sopenharmony_ci		return -EINVAL;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (slot_width &&
7698c2ecf20Sopenharmony_ci	    (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
7708c2ecf20Sopenharmony_ci		dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
7718c2ecf20Sopenharmony_ci			__func__, slot_width);
7728c2ecf20Sopenharmony_ci		return -EINVAL;
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	mcasp->tdm_slots = slots;
7768c2ecf20Sopenharmony_ci	mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
7778c2ecf20Sopenharmony_ci	mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
7788c2ecf20Sopenharmony_ci	mcasp->slot_width = slot_width;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return davinci_mcasp_set_ch_constraints(mcasp);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic int davinci_config_channel_size(struct davinci_mcasp *mcasp,
7848c2ecf20Sopenharmony_ci				       int sample_width)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	u32 fmt;
7878c2ecf20Sopenharmony_ci	u32 tx_rotate, rx_rotate, slot_width;
7888c2ecf20Sopenharmony_ci	u32 mask = (1ULL << sample_width) - 1;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (mcasp->slot_width)
7918c2ecf20Sopenharmony_ci		slot_width = mcasp->slot_width;
7928c2ecf20Sopenharmony_ci	else if (mcasp->max_format_width)
7938c2ecf20Sopenharmony_ci		slot_width = mcasp->max_format_width;
7948c2ecf20Sopenharmony_ci	else
7958c2ecf20Sopenharmony_ci		slot_width = sample_width;
7968c2ecf20Sopenharmony_ci	/*
7978c2ecf20Sopenharmony_ci	 * TX rotation:
7988c2ecf20Sopenharmony_ci	 * right aligned formats: rotate w/ slot_width
7998c2ecf20Sopenharmony_ci	 * left aligned formats: rotate w/ sample_width
8008c2ecf20Sopenharmony_ci	 *
8018c2ecf20Sopenharmony_ci	 * RX rotation:
8028c2ecf20Sopenharmony_ci	 * right aligned formats: no rotation needed
8038c2ecf20Sopenharmony_ci	 * left aligned formats: rotate w/ (slot_width - sample_width)
8048c2ecf20Sopenharmony_ci	 */
8058c2ecf20Sopenharmony_ci	if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
8068c2ecf20Sopenharmony_ci	    SND_SOC_DAIFMT_RIGHT_J) {
8078c2ecf20Sopenharmony_ci		tx_rotate = (slot_width / 4) & 0x7;
8088c2ecf20Sopenharmony_ci		rx_rotate = 0;
8098c2ecf20Sopenharmony_ci	} else {
8108c2ecf20Sopenharmony_ci		tx_rotate = (sample_width / 4) & 0x7;
8118c2ecf20Sopenharmony_ci		rx_rotate = (slot_width - sample_width) / 4;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/* mapping of the XSSZ bit-field as described in the datasheet */
8158c2ecf20Sopenharmony_ci	fmt = (slot_width >> 1) - 1;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
8188c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
8198c2ecf20Sopenharmony_ci			       RXSSZ(0x0F));
8208c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
8218c2ecf20Sopenharmony_ci			       TXSSZ(0x0F));
8228c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
8238c2ecf20Sopenharmony_ci			       TXROT(7));
8248c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
8258c2ecf20Sopenharmony_ci			       RXROT(7));
8268c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	return 0;
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
8358c2ecf20Sopenharmony_ci				 int period_words, int channels)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
8388c2ecf20Sopenharmony_ci	int i;
8398c2ecf20Sopenharmony_ci	u8 tx_ser = 0;
8408c2ecf20Sopenharmony_ci	u8 rx_ser = 0;
8418c2ecf20Sopenharmony_ci	u8 slots = mcasp->tdm_slots;
8428c2ecf20Sopenharmony_ci	u8 max_active_serializers = (channels + slots - 1) / slots;
8438c2ecf20Sopenharmony_ci	u8 max_rx_serializers, max_tx_serializers;
8448c2ecf20Sopenharmony_ci	int active_serializers, numevt;
8458c2ecf20Sopenharmony_ci	u32 reg;
8468c2ecf20Sopenharmony_ci	/* Default configuration */
8478c2ecf20Sopenharmony_ci	if (mcasp->version < MCASP_VERSION_3)
8488c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
8518c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
8528c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
8538c2ecf20Sopenharmony_ci		max_tx_serializers = max_active_serializers;
8548c2ecf20Sopenharmony_ci		max_rx_serializers =
8558c2ecf20Sopenharmony_ci			mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE];
8568c2ecf20Sopenharmony_ci	} else {
8578c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
8588c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
8598c2ecf20Sopenharmony_ci		max_tx_serializers =
8608c2ecf20Sopenharmony_ci			mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK];
8618c2ecf20Sopenharmony_ci		max_rx_serializers = max_active_serializers;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++) {
8658c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
8668c2ecf20Sopenharmony_ci			       mcasp->serial_dir[i]);
8678c2ecf20Sopenharmony_ci		if (mcasp->serial_dir[i] == TX_MODE &&
8688c2ecf20Sopenharmony_ci					tx_ser < max_tx_serializers) {
8698c2ecf20Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
8708c2ecf20Sopenharmony_ci				       mcasp->dismod, DISMOD_MASK);
8718c2ecf20Sopenharmony_ci			set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
8728c2ecf20Sopenharmony_ci			tx_ser++;
8738c2ecf20Sopenharmony_ci		} else if (mcasp->serial_dir[i] == RX_MODE &&
8748c2ecf20Sopenharmony_ci					rx_ser < max_rx_serializers) {
8758c2ecf20Sopenharmony_ci			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
8768c2ecf20Sopenharmony_ci			rx_ser++;
8778c2ecf20Sopenharmony_ci		} else {
8788c2ecf20Sopenharmony_ci			/* Inactive or unused pin, set it to inactive */
8798c2ecf20Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
8808c2ecf20Sopenharmony_ci				       SRMOD_INACTIVE, SRMOD_MASK);
8818c2ecf20Sopenharmony_ci			/* If unused, set DISMOD for the pin */
8828c2ecf20Sopenharmony_ci			if (mcasp->serial_dir[i] != INACTIVE_MODE)
8838c2ecf20Sopenharmony_ci				mcasp_mod_bits(mcasp,
8848c2ecf20Sopenharmony_ci					       DAVINCI_MCASP_XRSRCTL_REG(i),
8858c2ecf20Sopenharmony_ci					       mcasp->dismod, DISMOD_MASK);
8868c2ecf20Sopenharmony_ci			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
8918c2ecf20Sopenharmony_ci		active_serializers = tx_ser;
8928c2ecf20Sopenharmony_ci		numevt = mcasp->txnumevt;
8938c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
8948c2ecf20Sopenharmony_ci	} else {
8958c2ecf20Sopenharmony_ci		active_serializers = rx_ser;
8968c2ecf20Sopenharmony_ci		numevt = mcasp->rxnumevt;
8978c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (active_serializers < max_active_serializers) {
9018c2ecf20Sopenharmony_ci		dev_warn(mcasp->dev, "stream has more channels (%d) than are "
9028c2ecf20Sopenharmony_ci			 "enabled in mcasp (%d)\n", channels,
9038c2ecf20Sopenharmony_ci			 active_serializers * slots);
9048c2ecf20Sopenharmony_ci		return -EINVAL;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* AFIFO is not in use */
9088c2ecf20Sopenharmony_ci	if (!numevt) {
9098c2ecf20Sopenharmony_ci		/* Configure the burst size for platform drivers */
9108c2ecf20Sopenharmony_ci		if (active_serializers > 1) {
9118c2ecf20Sopenharmony_ci			/*
9128c2ecf20Sopenharmony_ci			 * If more than one serializers are in use we have one
9138c2ecf20Sopenharmony_ci			 * DMA request to provide data for all serializers.
9148c2ecf20Sopenharmony_ci			 * For example if three serializers are enabled the DMA
9158c2ecf20Sopenharmony_ci			 * need to transfer three words per DMA request.
9168c2ecf20Sopenharmony_ci			 */
9178c2ecf20Sopenharmony_ci			dma_data->maxburst = active_serializers;
9188c2ecf20Sopenharmony_ci		} else {
9198c2ecf20Sopenharmony_ci			dma_data->maxburst = 0;
9208c2ecf20Sopenharmony_ci		}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		goto out;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (period_words % active_serializers) {
9268c2ecf20Sopenharmony_ci		dev_err(mcasp->dev, "Invalid combination of period words and "
9278c2ecf20Sopenharmony_ci			"active serializers: %d, %d\n", period_words,
9288c2ecf20Sopenharmony_ci			active_serializers);
9298c2ecf20Sopenharmony_ci		return -EINVAL;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/*
9338c2ecf20Sopenharmony_ci	 * Calculate the optimal AFIFO depth for platform side:
9348c2ecf20Sopenharmony_ci	 * The number of words for numevt need to be in steps of active
9358c2ecf20Sopenharmony_ci	 * serializers.
9368c2ecf20Sopenharmony_ci	 */
9378c2ecf20Sopenharmony_ci	numevt = (numevt / active_serializers) * active_serializers;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	while (period_words % numevt && numevt > 0)
9408c2ecf20Sopenharmony_ci		numevt -= active_serializers;
9418c2ecf20Sopenharmony_ci	if (numevt <= 0)
9428c2ecf20Sopenharmony_ci		numevt = active_serializers;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
9458c2ecf20Sopenharmony_ci	mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* Configure the burst size for platform drivers */
9488c2ecf20Sopenharmony_ci	if (numevt == 1)
9498c2ecf20Sopenharmony_ci		numevt = 0;
9508c2ecf20Sopenharmony_ci	dma_data->maxburst = numevt;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ciout:
9538c2ecf20Sopenharmony_ci	mcasp->active_serializers[stream] = active_serializers;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return 0;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
9598c2ecf20Sopenharmony_ci			      int channels)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	int i, active_slots;
9628c2ecf20Sopenharmony_ci	int total_slots;
9638c2ecf20Sopenharmony_ci	int active_serializers;
9648c2ecf20Sopenharmony_ci	u32 mask = 0;
9658c2ecf20Sopenharmony_ci	u32 busel = 0;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	total_slots = mcasp->tdm_slots;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/*
9708c2ecf20Sopenharmony_ci	 * If more than one serializer is needed, then use them with
9718c2ecf20Sopenharmony_ci	 * all the specified tdm_slots. Otherwise, one serializer can
9728c2ecf20Sopenharmony_ci	 * cope with the transaction using just as many slots as there
9738c2ecf20Sopenharmony_ci	 * are channels in the stream.
9748c2ecf20Sopenharmony_ci	 */
9758c2ecf20Sopenharmony_ci	if (mcasp->tdm_mask[stream]) {
9768c2ecf20Sopenharmony_ci		active_slots = hweight32(mcasp->tdm_mask[stream]);
9778c2ecf20Sopenharmony_ci		active_serializers = (channels + active_slots - 1) /
9788c2ecf20Sopenharmony_ci			active_slots;
9798c2ecf20Sopenharmony_ci		if (active_serializers == 1)
9808c2ecf20Sopenharmony_ci			active_slots = channels;
9818c2ecf20Sopenharmony_ci		for (i = 0; i < total_slots; i++) {
9828c2ecf20Sopenharmony_ci			if ((1 << i) & mcasp->tdm_mask[stream]) {
9838c2ecf20Sopenharmony_ci				mask |= (1 << i);
9848c2ecf20Sopenharmony_ci				if (--active_slots <= 0)
9858c2ecf20Sopenharmony_ci					break;
9868c2ecf20Sopenharmony_ci			}
9878c2ecf20Sopenharmony_ci		}
9888c2ecf20Sopenharmony_ci	} else {
9898c2ecf20Sopenharmony_ci		active_serializers = (channels + total_slots - 1) / total_slots;
9908c2ecf20Sopenharmony_ci		if (active_serializers == 1)
9918c2ecf20Sopenharmony_ci			active_slots = channels;
9928c2ecf20Sopenharmony_ci		else
9938c2ecf20Sopenharmony_ci			active_slots = total_slots;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		for (i = 0; i < active_slots; i++)
9968c2ecf20Sopenharmony_ci			mask |= (1 << i);
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	if (!mcasp->dat_port)
10028c2ecf20Sopenharmony_ci		busel = TXSEL;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
10058c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
10068c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
10078c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
10088c2ecf20Sopenharmony_ci			       FSXMOD(total_slots), FSXMOD(0x1FF));
10098c2ecf20Sopenharmony_ci	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
10108c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
10118c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
10128c2ecf20Sopenharmony_ci		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
10138c2ecf20Sopenharmony_ci			       FSRMOD(total_slots), FSRMOD(0x1FF));
10148c2ecf20Sopenharmony_ci		/*
10158c2ecf20Sopenharmony_ci		 * If McASP is set to be TX/RX synchronous and the playback is
10168c2ecf20Sopenharmony_ci		 * not running already we need to configure the TX slots in
10178c2ecf20Sopenharmony_ci		 * order to have correct FSX on the bus
10188c2ecf20Sopenharmony_ci		 */
10198c2ecf20Sopenharmony_ci		if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
10208c2ecf20Sopenharmony_ci			mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
10218c2ecf20Sopenharmony_ci				       FSXMOD(total_slots), FSXMOD(0x1FF));
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	return 0;
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci/* S/PDIF */
10288c2ecf20Sopenharmony_cistatic int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
10298c2ecf20Sopenharmony_ci			      unsigned int rate)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	u32 cs_value = 0;
10328c2ecf20Sopenharmony_ci	u8 *cs_bytes = (u8*) &cs_value;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
10358c2ecf20Sopenharmony_ci	   and LSB first */
10368c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
10398c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* Set the TX tdm : for all the slots */
10428c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	/* Set the TX clock controls : div = 1 and internal */
10458c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* Only 44100 and 48000 are valid, both have the same setting */
10508c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	/* Enable the DIT */
10538c2ecf20Sopenharmony_ci	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Set S/PDIF channel status bits */
10568c2ecf20Sopenharmony_ci	cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
10578c2ecf20Sopenharmony_ci	cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	switch (rate) {
10608c2ecf20Sopenharmony_ci	case 22050:
10618c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
10628c2ecf20Sopenharmony_ci		break;
10638c2ecf20Sopenharmony_ci	case 24000:
10648c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
10658c2ecf20Sopenharmony_ci		break;
10668c2ecf20Sopenharmony_ci	case 32000:
10678c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
10688c2ecf20Sopenharmony_ci		break;
10698c2ecf20Sopenharmony_ci	case 44100:
10708c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
10718c2ecf20Sopenharmony_ci		break;
10728c2ecf20Sopenharmony_ci	case 48000:
10738c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
10748c2ecf20Sopenharmony_ci		break;
10758c2ecf20Sopenharmony_ci	case 88200:
10768c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
10778c2ecf20Sopenharmony_ci		break;
10788c2ecf20Sopenharmony_ci	case 96000:
10798c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
10808c2ecf20Sopenharmony_ci		break;
10818c2ecf20Sopenharmony_ci	case 176400:
10828c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
10838c2ecf20Sopenharmony_ci		break;
10848c2ecf20Sopenharmony_ci	case 192000:
10858c2ecf20Sopenharmony_ci		cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
10868c2ecf20Sopenharmony_ci		break;
10878c2ecf20Sopenharmony_ci	default:
10888c2ecf20Sopenharmony_ci		printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
10898c2ecf20Sopenharmony_ci		return -EINVAL;
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
10938c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	return 0;
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
10998c2ecf20Sopenharmony_ci				      unsigned int sysclk_freq,
11008c2ecf20Sopenharmony_ci				      unsigned int bclk_freq, bool set)
11018c2ecf20Sopenharmony_ci{
11028c2ecf20Sopenharmony_ci	u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
11038c2ecf20Sopenharmony_ci	int div = sysclk_freq / bclk_freq;
11048c2ecf20Sopenharmony_ci	int rem = sysclk_freq % bclk_freq;
11058c2ecf20Sopenharmony_ci	int error_ppm;
11068c2ecf20Sopenharmony_ci	int aux_div = 1;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (div > (ACLKXDIV_MASK + 1)) {
11098c2ecf20Sopenharmony_ci		if (reg & AHCLKXE) {
11108c2ecf20Sopenharmony_ci			aux_div = div / (ACLKXDIV_MASK + 1);
11118c2ecf20Sopenharmony_ci			if (div % (ACLKXDIV_MASK + 1))
11128c2ecf20Sopenharmony_ci				aux_div++;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci			sysclk_freq /= aux_div;
11158c2ecf20Sopenharmony_ci			div = sysclk_freq / bclk_freq;
11168c2ecf20Sopenharmony_ci			rem = sysclk_freq % bclk_freq;
11178c2ecf20Sopenharmony_ci		} else if (set) {
11188c2ecf20Sopenharmony_ci			dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
11198c2ecf20Sopenharmony_ci				 sysclk_freq);
11208c2ecf20Sopenharmony_ci		}
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	if (rem != 0) {
11248c2ecf20Sopenharmony_ci		if (div == 0 ||
11258c2ecf20Sopenharmony_ci		    ((sysclk_freq / div) - bclk_freq) >
11268c2ecf20Sopenharmony_ci		    (bclk_freq - (sysclk_freq / (div+1)))) {
11278c2ecf20Sopenharmony_ci			div++;
11288c2ecf20Sopenharmony_ci			rem = rem - bclk_freq;
11298c2ecf20Sopenharmony_ci		}
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci	error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
11328c2ecf20Sopenharmony_ci		     (int)bclk_freq)) / div - 1000000;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	if (set) {
11358c2ecf20Sopenharmony_ci		if (error_ppm)
11368c2ecf20Sopenharmony_ci			dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
11378c2ecf20Sopenharmony_ci				 error_ppm);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
11408c2ecf20Sopenharmony_ci		if (reg & AHCLKXE)
11418c2ecf20Sopenharmony_ci			__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
11428c2ecf20Sopenharmony_ci						   aux_div, 0);
11438c2ecf20Sopenharmony_ci	}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	return error_ppm;
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	if (!mcasp->txnumevt)
11518c2ecf20Sopenharmony_ci		return 0;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	if (!mcasp->rxnumevt)
11598c2ecf20Sopenharmony_ci		return 0;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_cistatic snd_pcm_sframes_t davinci_mcasp_delay(
11658c2ecf20Sopenharmony_ci			struct snd_pcm_substream *substream,
11668c2ecf20Sopenharmony_ci			struct snd_soc_dai *cpu_dai)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
11698c2ecf20Sopenharmony_ci	u32 fifo_use;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
11728c2ecf20Sopenharmony_ci		fifo_use = davinci_mcasp_tx_delay(mcasp);
11738c2ecf20Sopenharmony_ci	else
11748c2ecf20Sopenharmony_ci		fifo_use = davinci_mcasp_rx_delay(mcasp);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	/*
11778c2ecf20Sopenharmony_ci	 * Divide the used locations with the channel count to get the
11788c2ecf20Sopenharmony_ci	 * FIFO usage in samples (don't care about partial samples in the
11798c2ecf20Sopenharmony_ci	 * buffer).
11808c2ecf20Sopenharmony_ci	 */
11818c2ecf20Sopenharmony_ci	return fifo_use / substream->runtime->channels;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
11858c2ecf20Sopenharmony_ci					struct snd_pcm_hw_params *params,
11868c2ecf20Sopenharmony_ci					struct snd_soc_dai *cpu_dai)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
11898c2ecf20Sopenharmony_ci	int word_length;
11908c2ecf20Sopenharmony_ci	int channels = params_channels(params);
11918c2ecf20Sopenharmony_ci	int period_size = params_period_size(params);
11928c2ecf20Sopenharmony_ci	int ret;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	switch (params_format(params)) {
11958c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U8:
11968c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
11978c2ecf20Sopenharmony_ci		word_length = 8;
11988c2ecf20Sopenharmony_ci		break;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U16_LE:
12018c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
12028c2ecf20Sopenharmony_ci		word_length = 16;
12038c2ecf20Sopenharmony_ci		break;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U24_3LE:
12068c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_3LE:
12078c2ecf20Sopenharmony_ci		word_length = 24;
12088c2ecf20Sopenharmony_ci		break;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U24_LE:
12118c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
12128c2ecf20Sopenharmony_ci		word_length = 24;
12138c2ecf20Sopenharmony_ci		break;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U32_LE:
12168c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
12178c2ecf20Sopenharmony_ci		word_length = 32;
12188c2ecf20Sopenharmony_ci		break;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	default:
12218c2ecf20Sopenharmony_ci		printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
12228c2ecf20Sopenharmony_ci		return -EINVAL;
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt);
12268c2ecf20Sopenharmony_ci	if (ret)
12278c2ecf20Sopenharmony_ci		return ret;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/*
12308c2ecf20Sopenharmony_ci	 * If mcasp is BCLK master, and a BCLK divider was not provided by
12318c2ecf20Sopenharmony_ci	 * the machine driver, we need to calculate the ratio.
12328c2ecf20Sopenharmony_ci	 */
12338c2ecf20Sopenharmony_ci	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
12348c2ecf20Sopenharmony_ci		int slots = mcasp->tdm_slots;
12358c2ecf20Sopenharmony_ci		int rate = params_rate(params);
12368c2ecf20Sopenharmony_ci		int sbits = params_width(params);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci		if (mcasp->slot_width)
12398c2ecf20Sopenharmony_ci			sbits = mcasp->slot_width;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
12428c2ecf20Sopenharmony_ci					   rate * sbits * slots, true);
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	ret = mcasp_common_hw_param(mcasp, substream->stream,
12468c2ecf20Sopenharmony_ci				    period_size * channels, channels);
12478c2ecf20Sopenharmony_ci	if (ret)
12488c2ecf20Sopenharmony_ci		return ret;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
12518c2ecf20Sopenharmony_ci		ret = mcasp_dit_hw_param(mcasp, params_rate(params));
12528c2ecf20Sopenharmony_ci	else
12538c2ecf20Sopenharmony_ci		ret = mcasp_i2s_hw_param(mcasp, substream->stream,
12548c2ecf20Sopenharmony_ci					 channels);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	if (ret)
12578c2ecf20Sopenharmony_ci		return ret;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	davinci_config_channel_size(mcasp, word_length);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
12628c2ecf20Sopenharmony_ci		mcasp->channels = channels;
12638c2ecf20Sopenharmony_ci		if (!mcasp->max_format_width)
12648c2ecf20Sopenharmony_ci			mcasp->max_format_width = word_length;
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return 0;
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
12718c2ecf20Sopenharmony_ci				     int cmd, struct snd_soc_dai *cpu_dai)
12728c2ecf20Sopenharmony_ci{
12738c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
12748c2ecf20Sopenharmony_ci	int ret = 0;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	switch (cmd) {
12778c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
12788c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
12798c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
12808c2ecf20Sopenharmony_ci		davinci_mcasp_start(mcasp, substream->stream);
12818c2ecf20Sopenharmony_ci		break;
12828c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
12838c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
12848c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
12858c2ecf20Sopenharmony_ci		davinci_mcasp_stop(mcasp, substream->stream);
12868c2ecf20Sopenharmony_ci		break;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	default:
12898c2ecf20Sopenharmony_ci		ret = -EINVAL;
12908c2ecf20Sopenharmony_ci	}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	return ret;
12938c2ecf20Sopenharmony_ci}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
12968c2ecf20Sopenharmony_ci					    struct snd_pcm_hw_rule *rule)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
12998c2ecf20Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
13008c2ecf20Sopenharmony_ci	struct snd_mask nfmt;
13018c2ecf20Sopenharmony_ci	int i, slot_width;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	snd_mask_none(&nfmt);
13048c2ecf20Sopenharmony_ci	slot_width = rd->mcasp->slot_width;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
13078c2ecf20Sopenharmony_ci		if (snd_mask_test(fmt, i)) {
13088c2ecf20Sopenharmony_ci			if (snd_pcm_format_width(i) <= slot_width) {
13098c2ecf20Sopenharmony_ci				snd_mask_set(&nfmt, i);
13108c2ecf20Sopenharmony_ci			}
13118c2ecf20Sopenharmony_ci		}
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
13158c2ecf20Sopenharmony_ci}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params,
13188c2ecf20Sopenharmony_ci					      struct snd_pcm_hw_rule *rule)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
13218c2ecf20Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
13228c2ecf20Sopenharmony_ci	struct snd_mask nfmt;
13238c2ecf20Sopenharmony_ci	int i, format_width;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	snd_mask_none(&nfmt);
13268c2ecf20Sopenharmony_ci	format_width = rd->mcasp->max_format_width;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
13298c2ecf20Sopenharmony_ci		if (snd_mask_test(fmt, i)) {
13308c2ecf20Sopenharmony_ci			if (snd_pcm_format_width(i) == format_width) {
13318c2ecf20Sopenharmony_ci				snd_mask_set(&nfmt, i);
13328c2ecf20Sopenharmony_ci			}
13338c2ecf20Sopenharmony_ci		}
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
13378c2ecf20Sopenharmony_ci}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_cistatic const unsigned int davinci_mcasp_dai_rates[] = {
13408c2ecf20Sopenharmony_ci	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
13418c2ecf20Sopenharmony_ci	88200, 96000, 176400, 192000,
13428c2ecf20Sopenharmony_ci};
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci#define DAVINCI_MAX_RATE_ERROR_PPM 1000
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
13478c2ecf20Sopenharmony_ci				      struct snd_pcm_hw_rule *rule)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
13508c2ecf20Sopenharmony_ci	struct snd_interval *ri =
13518c2ecf20Sopenharmony_ci		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
13528c2ecf20Sopenharmony_ci	int sbits = params_width(params);
13538c2ecf20Sopenharmony_ci	int slots = rd->mcasp->tdm_slots;
13548c2ecf20Sopenharmony_ci	struct snd_interval range;
13558c2ecf20Sopenharmony_ci	int i;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (rd->mcasp->slot_width)
13588c2ecf20Sopenharmony_ci		sbits = rd->mcasp->slot_width;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	snd_interval_any(&range);
13618c2ecf20Sopenharmony_ci	range.empty = 1;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
13648c2ecf20Sopenharmony_ci		if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
13658c2ecf20Sopenharmony_ci			uint bclk_freq = sbits * slots *
13668c2ecf20Sopenharmony_ci					 davinci_mcasp_dai_rates[i];
13678c2ecf20Sopenharmony_ci			unsigned int sysclk_freq;
13688c2ecf20Sopenharmony_ci			int ppm;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci			if (rd->mcasp->auxclk_fs_ratio)
13718c2ecf20Sopenharmony_ci				sysclk_freq =  davinci_mcasp_dai_rates[i] *
13728c2ecf20Sopenharmony_ci					       rd->mcasp->auxclk_fs_ratio;
13738c2ecf20Sopenharmony_ci			else
13748c2ecf20Sopenharmony_ci				sysclk_freq = rd->mcasp->sysclk_freq;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
13778c2ecf20Sopenharmony_ci							 bclk_freq, false);
13788c2ecf20Sopenharmony_ci			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
13798c2ecf20Sopenharmony_ci				if (range.empty) {
13808c2ecf20Sopenharmony_ci					range.min = davinci_mcasp_dai_rates[i];
13818c2ecf20Sopenharmony_ci					range.empty = 0;
13828c2ecf20Sopenharmony_ci				}
13838c2ecf20Sopenharmony_ci				range.max = davinci_mcasp_dai_rates[i];
13848c2ecf20Sopenharmony_ci			}
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	dev_dbg(rd->mcasp->dev,
13898c2ecf20Sopenharmony_ci		"Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
13908c2ecf20Sopenharmony_ci		ri->min, ri->max, range.min, range.max, sbits, slots);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, rule->var),
13938c2ecf20Sopenharmony_ci				   &range);
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
13978c2ecf20Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata *rd = rule->private;
14008c2ecf20Sopenharmony_ci	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
14018c2ecf20Sopenharmony_ci	struct snd_mask nfmt;
14028c2ecf20Sopenharmony_ci	int rate = params_rate(params);
14038c2ecf20Sopenharmony_ci	int slots = rd->mcasp->tdm_slots;
14048c2ecf20Sopenharmony_ci	int i, count = 0;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	snd_mask_none(&nfmt);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
14098c2ecf20Sopenharmony_ci		if (snd_mask_test(fmt, i)) {
14108c2ecf20Sopenharmony_ci			uint sbits = snd_pcm_format_width(i);
14118c2ecf20Sopenharmony_ci			unsigned int sysclk_freq;
14128c2ecf20Sopenharmony_ci			int ppm;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci			if (rd->mcasp->auxclk_fs_ratio)
14158c2ecf20Sopenharmony_ci				sysclk_freq =  rate *
14168c2ecf20Sopenharmony_ci					       rd->mcasp->auxclk_fs_ratio;
14178c2ecf20Sopenharmony_ci			else
14188c2ecf20Sopenharmony_ci				sysclk_freq = rd->mcasp->sysclk_freq;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci			if (rd->mcasp->slot_width)
14218c2ecf20Sopenharmony_ci				sbits = rd->mcasp->slot_width;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
14248c2ecf20Sopenharmony_ci							 sbits * slots * rate,
14258c2ecf20Sopenharmony_ci							 false);
14268c2ecf20Sopenharmony_ci			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
14278c2ecf20Sopenharmony_ci				snd_mask_set(&nfmt, i);
14288c2ecf20Sopenharmony_ci				count++;
14298c2ecf20Sopenharmony_ci			}
14308c2ecf20Sopenharmony_ci		}
14318c2ecf20Sopenharmony_ci	}
14328c2ecf20Sopenharmony_ci	dev_dbg(rd->mcasp->dev,
14338c2ecf20Sopenharmony_ci		"%d possible sample format for %d Hz and %d tdm slots\n",
14348c2ecf20Sopenharmony_ci		count, rate, slots);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	return snd_mask_refine(fmt, &nfmt);
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_min_periodsize(
14408c2ecf20Sopenharmony_ci		struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
14418c2ecf20Sopenharmony_ci{
14428c2ecf20Sopenharmony_ci	struct snd_interval *period_size = hw_param_interval(params,
14438c2ecf20Sopenharmony_ci						SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
14448c2ecf20Sopenharmony_ci	struct snd_interval frames;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	snd_interval_any(&frames);
14478c2ecf20Sopenharmony_ci	frames.min = 64;
14488c2ecf20Sopenharmony_ci	frames.integer = 1;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	return snd_interval_refine(period_size, &frames);
14518c2ecf20Sopenharmony_ci}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_cistatic int davinci_mcasp_startup(struct snd_pcm_substream *substream,
14548c2ecf20Sopenharmony_ci				 struct snd_soc_dai *cpu_dai)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
14578c2ecf20Sopenharmony_ci	struct davinci_mcasp_ruledata *ruledata =
14588c2ecf20Sopenharmony_ci					&mcasp->ruledata[substream->stream];
14598c2ecf20Sopenharmony_ci	u32 max_channels = 0;
14608c2ecf20Sopenharmony_ci	int i, dir, ret;
14618c2ecf20Sopenharmony_ci	int tdm_slots = mcasp->tdm_slots;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/* Do not allow more then one stream per direction */
14648c2ecf20Sopenharmony_ci	if (mcasp->substreams[substream->stream])
14658c2ecf20Sopenharmony_ci		return -EBUSY;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	mcasp->substreams[substream->stream] = substream;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	if (mcasp->tdm_mask[substream->stream])
14708c2ecf20Sopenharmony_ci		tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
14738c2ecf20Sopenharmony_ci		return 0;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/*
14768c2ecf20Sopenharmony_ci	 * Limit the maximum allowed channels for the first stream:
14778c2ecf20Sopenharmony_ci	 * number of serializers for the direction * tdm slots per serializer
14788c2ecf20Sopenharmony_ci	 */
14798c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
14808c2ecf20Sopenharmony_ci		dir = TX_MODE;
14818c2ecf20Sopenharmony_ci	else
14828c2ecf20Sopenharmony_ci		dir = RX_MODE;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++) {
14858c2ecf20Sopenharmony_ci		if (mcasp->serial_dir[i] == dir)
14868c2ecf20Sopenharmony_ci			max_channels++;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci	ruledata->serializers = max_channels;
14898c2ecf20Sopenharmony_ci	ruledata->mcasp = mcasp;
14908c2ecf20Sopenharmony_ci	max_channels *= tdm_slots;
14918c2ecf20Sopenharmony_ci	/*
14928c2ecf20Sopenharmony_ci	 * If the already active stream has less channels than the calculated
14938c2ecf20Sopenharmony_ci	 * limit based on the seirializers * tdm_slots, and only one serializer
14948c2ecf20Sopenharmony_ci	 * is in use we need to use that as a constraint for the second stream.
14958c2ecf20Sopenharmony_ci	 * Otherwise (first stream or less allowed channels or more than one
14968c2ecf20Sopenharmony_ci	 * serializer in use) we use the calculated constraint.
14978c2ecf20Sopenharmony_ci	 */
14988c2ecf20Sopenharmony_ci	if (mcasp->channels && mcasp->channels < max_channels &&
14998c2ecf20Sopenharmony_ci	    ruledata->serializers == 1)
15008c2ecf20Sopenharmony_ci		max_channels = mcasp->channels;
15018c2ecf20Sopenharmony_ci	/*
15028c2ecf20Sopenharmony_ci	 * But we can always allow channels upto the amount of
15038c2ecf20Sopenharmony_ci	 * the available tdm_slots.
15048c2ecf20Sopenharmony_ci	 */
15058c2ecf20Sopenharmony_ci	if (max_channels < tdm_slots)
15068c2ecf20Sopenharmony_ci		max_channels = tdm_slots;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_minmax(substream->runtime,
15098c2ecf20Sopenharmony_ci				     SNDRV_PCM_HW_PARAM_CHANNELS,
15108c2ecf20Sopenharmony_ci				     0, max_channels);
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_list(substream->runtime,
15138c2ecf20Sopenharmony_ci				   0, SNDRV_PCM_HW_PARAM_CHANNELS,
15148c2ecf20Sopenharmony_ci				   &mcasp->chconstr[substream->stream]);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (mcasp->max_format_width) {
15178c2ecf20Sopenharmony_ci		/*
15188c2ecf20Sopenharmony_ci		 * Only allow formats which require same amount of bits on the
15198c2ecf20Sopenharmony_ci		 * bus as the currently running stream
15208c2ecf20Sopenharmony_ci		 */
15218c2ecf20Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15228c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
15238c2ecf20Sopenharmony_ci					  davinci_mcasp_hw_rule_format_width,
15248c2ecf20Sopenharmony_ci					  ruledata,
15258c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
15268c2ecf20Sopenharmony_ci		if (ret)
15278c2ecf20Sopenharmony_ci			return ret;
15288c2ecf20Sopenharmony_ci	}
15298c2ecf20Sopenharmony_ci	else if (mcasp->slot_width) {
15308c2ecf20Sopenharmony_ci		/* Only allow formats require <= slot_width bits on the bus */
15318c2ecf20Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15328c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
15338c2ecf20Sopenharmony_ci					  davinci_mcasp_hw_rule_slot_width,
15348c2ecf20Sopenharmony_ci					  ruledata,
15358c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
15368c2ecf20Sopenharmony_ci		if (ret)
15378c2ecf20Sopenharmony_ci			return ret;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	/*
15418c2ecf20Sopenharmony_ci	 * If we rely on implicit BCLK divider setting we should
15428c2ecf20Sopenharmony_ci	 * set constraints based on what we can provide.
15438c2ecf20Sopenharmony_ci	 */
15448c2ecf20Sopenharmony_ci	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
15458c2ecf20Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15468c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_RATE,
15478c2ecf20Sopenharmony_ci					  davinci_mcasp_hw_rule_rate,
15488c2ecf20Sopenharmony_ci					  ruledata,
15498c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
15508c2ecf20Sopenharmony_ci		if (ret)
15518c2ecf20Sopenharmony_ci			return ret;
15528c2ecf20Sopenharmony_ci		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15538c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_FORMAT,
15548c2ecf20Sopenharmony_ci					  davinci_mcasp_hw_rule_format,
15558c2ecf20Sopenharmony_ci					  ruledata,
15568c2ecf20Sopenharmony_ci					  SNDRV_PCM_HW_PARAM_RATE, -1);
15578c2ecf20Sopenharmony_ci		if (ret)
15588c2ecf20Sopenharmony_ci			return ret;
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(substream->runtime, 0,
15628c2ecf20Sopenharmony_ci			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
15638c2ecf20Sopenharmony_ci			    davinci_mcasp_hw_rule_min_periodsize, NULL,
15648c2ecf20Sopenharmony_ci			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	return 0;
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
15708c2ecf20Sopenharmony_ci				   struct snd_soc_dai *cpu_dai)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	mcasp->substreams[substream->stream] = NULL;
15758c2ecf20Sopenharmony_ci	mcasp->active_serializers[substream->stream] = 0;
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
15788c2ecf20Sopenharmony_ci		return;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(cpu_dai)) {
15818c2ecf20Sopenharmony_ci		mcasp->channels = 0;
15828c2ecf20Sopenharmony_ci		mcasp->max_format_width = 0;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
15878c2ecf20Sopenharmony_ci	.startup	= davinci_mcasp_startup,
15888c2ecf20Sopenharmony_ci	.shutdown	= davinci_mcasp_shutdown,
15898c2ecf20Sopenharmony_ci	.trigger	= davinci_mcasp_trigger,
15908c2ecf20Sopenharmony_ci	.delay		= davinci_mcasp_delay,
15918c2ecf20Sopenharmony_ci	.hw_params	= davinci_mcasp_hw_params,
15928c2ecf20Sopenharmony_ci	.set_fmt	= davinci_mcasp_set_dai_fmt,
15938c2ecf20Sopenharmony_ci	.set_clkdiv	= davinci_mcasp_set_clkdiv,
15948c2ecf20Sopenharmony_ci	.set_sysclk	= davinci_mcasp_set_sysclk,
15958c2ecf20Sopenharmony_ci	.set_tdm_slot	= davinci_mcasp_set_tdm_slot,
15968c2ecf20Sopenharmony_ci};
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_cistatic int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
16038c2ecf20Sopenharmony_ci	dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	return 0;
16068c2ecf20Sopenharmony_ci}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci#define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_192000
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
16118c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_U8 | \
16128c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S16_LE | \
16138c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_U16_LE | \
16148c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_LE | \
16158c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_U24_LE | \
16168c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_3LE | \
16178c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_U24_3LE | \
16188c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S32_LE | \
16198c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_U32_LE)
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver davinci_mcasp_dai[] = {
16228c2ecf20Sopenharmony_ci	{
16238c2ecf20Sopenharmony_ci		.name		= "davinci-mcasp.0",
16248c2ecf20Sopenharmony_ci		.probe		= davinci_mcasp_dai_probe,
16258c2ecf20Sopenharmony_ci		.playback	= {
16268c2ecf20Sopenharmony_ci			.stream_name = "IIS Playback",
16278c2ecf20Sopenharmony_ci			.channels_min	= 1,
16288c2ecf20Sopenharmony_ci			.channels_max	= 32 * 16,
16298c2ecf20Sopenharmony_ci			.rates 		= DAVINCI_MCASP_RATES,
16308c2ecf20Sopenharmony_ci			.formats	= DAVINCI_MCASP_PCM_FMTS,
16318c2ecf20Sopenharmony_ci		},
16328c2ecf20Sopenharmony_ci		.capture 	= {
16338c2ecf20Sopenharmony_ci			.stream_name = "IIS Capture",
16348c2ecf20Sopenharmony_ci			.channels_min 	= 1,
16358c2ecf20Sopenharmony_ci			.channels_max	= 32 * 16,
16368c2ecf20Sopenharmony_ci			.rates 		= DAVINCI_MCASP_RATES,
16378c2ecf20Sopenharmony_ci			.formats	= DAVINCI_MCASP_PCM_FMTS,
16388c2ecf20Sopenharmony_ci		},
16398c2ecf20Sopenharmony_ci		.ops 		= &davinci_mcasp_dai_ops,
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		.symmetric_rates	= 1,
16428c2ecf20Sopenharmony_ci	},
16438c2ecf20Sopenharmony_ci	{
16448c2ecf20Sopenharmony_ci		.name		= "davinci-mcasp.1",
16458c2ecf20Sopenharmony_ci		.probe		= davinci_mcasp_dai_probe,
16468c2ecf20Sopenharmony_ci		.playback 	= {
16478c2ecf20Sopenharmony_ci			.stream_name = "DIT Playback",
16488c2ecf20Sopenharmony_ci			.channels_min	= 1,
16498c2ecf20Sopenharmony_ci			.channels_max	= 384,
16508c2ecf20Sopenharmony_ci			.rates		= DAVINCI_MCASP_RATES,
16518c2ecf20Sopenharmony_ci			.formats	= DAVINCI_MCASP_PCM_FMTS,
16528c2ecf20Sopenharmony_ci		},
16538c2ecf20Sopenharmony_ci		.ops 		= &davinci_mcasp_dai_ops,
16548c2ecf20Sopenharmony_ci	},
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci};
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver davinci_mcasp_component = {
16598c2ecf20Sopenharmony_ci	.name		= "davinci-mcasp",
16608c2ecf20Sopenharmony_ci};
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci/* Some HW specific values and defaults. The rest is filled in from DT. */
16638c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
16648c2ecf20Sopenharmony_ci	.tx_dma_offset = 0x400,
16658c2ecf20Sopenharmony_ci	.rx_dma_offset = 0x400,
16668c2ecf20Sopenharmony_ci	.version = MCASP_VERSION_1,
16678c2ecf20Sopenharmony_ci};
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata da830_mcasp_pdata = {
16708c2ecf20Sopenharmony_ci	.tx_dma_offset = 0x2000,
16718c2ecf20Sopenharmony_ci	.rx_dma_offset = 0x2000,
16728c2ecf20Sopenharmony_ci	.version = MCASP_VERSION_2,
16738c2ecf20Sopenharmony_ci};
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
16768c2ecf20Sopenharmony_ci	.tx_dma_offset = 0,
16778c2ecf20Sopenharmony_ci	.rx_dma_offset = 0,
16788c2ecf20Sopenharmony_ci	.version = MCASP_VERSION_3,
16798c2ecf20Sopenharmony_ci};
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata dra7_mcasp_pdata = {
16828c2ecf20Sopenharmony_ci	/* The CFG port offset will be calculated if it is needed */
16838c2ecf20Sopenharmony_ci	.tx_dma_offset = 0,
16848c2ecf20Sopenharmony_ci	.rx_dma_offset = 0,
16858c2ecf20Sopenharmony_ci	.version = MCASP_VERSION_4,
16868c2ecf20Sopenharmony_ci};
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_cistatic const struct of_device_id mcasp_dt_ids[] = {
16898c2ecf20Sopenharmony_ci	{
16908c2ecf20Sopenharmony_ci		.compatible = "ti,dm646x-mcasp-audio",
16918c2ecf20Sopenharmony_ci		.data = &dm646x_mcasp_pdata,
16928c2ecf20Sopenharmony_ci	},
16938c2ecf20Sopenharmony_ci	{
16948c2ecf20Sopenharmony_ci		.compatible = "ti,da830-mcasp-audio",
16958c2ecf20Sopenharmony_ci		.data = &da830_mcasp_pdata,
16968c2ecf20Sopenharmony_ci	},
16978c2ecf20Sopenharmony_ci	{
16988c2ecf20Sopenharmony_ci		.compatible = "ti,am33xx-mcasp-audio",
16998c2ecf20Sopenharmony_ci		.data = &am33xx_mcasp_pdata,
17008c2ecf20Sopenharmony_ci	},
17018c2ecf20Sopenharmony_ci	{
17028c2ecf20Sopenharmony_ci		.compatible = "ti,dra7-mcasp-audio",
17038c2ecf20Sopenharmony_ci		.data = &dra7_mcasp_pdata,
17048c2ecf20Sopenharmony_ci	},
17058c2ecf20Sopenharmony_ci	{ /* sentinel */ }
17068c2ecf20Sopenharmony_ci};
17078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mcasp_dt_ids);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_cistatic int mcasp_reparent_fck(struct platform_device *pdev)
17108c2ecf20Sopenharmony_ci{
17118c2ecf20Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
17128c2ecf20Sopenharmony_ci	struct clk *gfclk, *parent_clk;
17138c2ecf20Sopenharmony_ci	const char *parent_name;
17148c2ecf20Sopenharmony_ci	int ret;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	if (!node)
17178c2ecf20Sopenharmony_ci		return 0;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	parent_name = of_get_property(node, "fck_parent", NULL);
17208c2ecf20Sopenharmony_ci	if (!parent_name)
17218c2ecf20Sopenharmony_ci		return 0;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	gfclk = clk_get(&pdev->dev, "fck");
17268c2ecf20Sopenharmony_ci	if (IS_ERR(gfclk)) {
17278c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get fck\n");
17288c2ecf20Sopenharmony_ci		return PTR_ERR(gfclk);
17298c2ecf20Sopenharmony_ci	}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	parent_clk = clk_get(NULL, parent_name);
17328c2ecf20Sopenharmony_ci	if (IS_ERR(parent_clk)) {
17338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get parent clock\n");
17348c2ecf20Sopenharmony_ci		ret = PTR_ERR(parent_clk);
17358c2ecf20Sopenharmony_ci		goto err1;
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	ret = clk_set_parent(gfclk, parent_clk);
17398c2ecf20Sopenharmony_ci	if (ret) {
17408c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to reparent fck\n");
17418c2ecf20Sopenharmony_ci		goto err2;
17428c2ecf20Sopenharmony_ci	}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_cierr2:
17458c2ecf20Sopenharmony_ci	clk_put(parent_clk);
17468c2ecf20Sopenharmony_cierr1:
17478c2ecf20Sopenharmony_ci	clk_put(gfclk);
17488c2ecf20Sopenharmony_ci	return ret;
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
17528c2ecf20Sopenharmony_ci						struct platform_device *pdev)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
17558c2ecf20Sopenharmony_ci	struct davinci_mcasp_pdata *pdata = NULL;
17568c2ecf20Sopenharmony_ci	const struct of_device_id *match =
17578c2ecf20Sopenharmony_ci			of_match_device(mcasp_dt_ids, &pdev->dev);
17588c2ecf20Sopenharmony_ci	struct of_phandle_args dma_spec;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	const u32 *of_serial_dir32;
17618c2ecf20Sopenharmony_ci	u32 val;
17628c2ecf20Sopenharmony_ci	int i, ret = 0;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	if (pdev->dev.platform_data) {
17658c2ecf20Sopenharmony_ci		pdata = pdev->dev.platform_data;
17668c2ecf20Sopenharmony_ci		pdata->dismod = DISMOD_LOW;
17678c2ecf20Sopenharmony_ci		return pdata;
17688c2ecf20Sopenharmony_ci	} else if (match) {
17698c2ecf20Sopenharmony_ci		pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
17708c2ecf20Sopenharmony_ci				     GFP_KERNEL);
17718c2ecf20Sopenharmony_ci		if (!pdata)
17728c2ecf20Sopenharmony_ci			return NULL;
17738c2ecf20Sopenharmony_ci	} else {
17748c2ecf20Sopenharmony_ci		/* control shouldn't reach here. something is wrong */
17758c2ecf20Sopenharmony_ci		ret = -EINVAL;
17768c2ecf20Sopenharmony_ci		goto nodata;
17778c2ecf20Sopenharmony_ci	}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "op-mode", &val);
17808c2ecf20Sopenharmony_ci	if (ret >= 0)
17818c2ecf20Sopenharmony_ci		pdata->op_mode = val;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "tdm-slots", &val);
17848c2ecf20Sopenharmony_ci	if (ret >= 0) {
17858c2ecf20Sopenharmony_ci		if (val < 2 || val > 32) {
17868c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
17878c2ecf20Sopenharmony_ci				"tdm-slots must be in rage [2-32]\n");
17888c2ecf20Sopenharmony_ci			ret = -EINVAL;
17898c2ecf20Sopenharmony_ci			goto nodata;
17908c2ecf20Sopenharmony_ci		}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		pdata->tdm_slots = val;
17938c2ecf20Sopenharmony_ci	}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	of_serial_dir32 = of_get_property(np, "serial-dir", &val);
17968c2ecf20Sopenharmony_ci	val /= sizeof(u32);
17978c2ecf20Sopenharmony_ci	if (of_serial_dir32) {
17988c2ecf20Sopenharmony_ci		u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
17998c2ecf20Sopenharmony_ci						 (sizeof(*of_serial_dir) * val),
18008c2ecf20Sopenharmony_ci						 GFP_KERNEL);
18018c2ecf20Sopenharmony_ci		if (!of_serial_dir) {
18028c2ecf20Sopenharmony_ci			ret = -ENOMEM;
18038c2ecf20Sopenharmony_ci			goto nodata;
18048c2ecf20Sopenharmony_ci		}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		for (i = 0; i < val; i++)
18078c2ecf20Sopenharmony_ci			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci		pdata->num_serializer = val;
18108c2ecf20Sopenharmony_ci		pdata->serial_dir = of_serial_dir;
18118c2ecf20Sopenharmony_ci	}
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	ret = of_property_match_string(np, "dma-names", "tx");
18148c2ecf20Sopenharmony_ci	if (ret < 0)
18158c2ecf20Sopenharmony_ci		goto nodata;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
18188c2ecf20Sopenharmony_ci					 &dma_spec);
18198c2ecf20Sopenharmony_ci	if (ret < 0)
18208c2ecf20Sopenharmony_ci		goto nodata;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	pdata->tx_dma_channel = dma_spec.args[0];
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	/* RX is not valid in DIT mode */
18258c2ecf20Sopenharmony_ci	if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
18268c2ecf20Sopenharmony_ci		ret = of_property_match_string(np, "dma-names", "rx");
18278c2ecf20Sopenharmony_ci		if (ret < 0)
18288c2ecf20Sopenharmony_ci			goto nodata;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
18318c2ecf20Sopenharmony_ci						 &dma_spec);
18328c2ecf20Sopenharmony_ci		if (ret < 0)
18338c2ecf20Sopenharmony_ci			goto nodata;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci		pdata->rx_dma_channel = dma_spec.args[0];
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "tx-num-evt", &val);
18398c2ecf20Sopenharmony_ci	if (ret >= 0)
18408c2ecf20Sopenharmony_ci		pdata->txnumevt = val;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "rx-num-evt", &val);
18438c2ecf20Sopenharmony_ci	if (ret >= 0)
18448c2ecf20Sopenharmony_ci		pdata->rxnumevt = val;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "sram-size-playback", &val);
18478c2ecf20Sopenharmony_ci	if (ret >= 0)
18488c2ecf20Sopenharmony_ci		pdata->sram_size_playback = val;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "sram-size-capture", &val);
18518c2ecf20Sopenharmony_ci	if (ret >= 0)
18528c2ecf20Sopenharmony_ci		pdata->sram_size_capture = val;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "dismod", &val);
18558c2ecf20Sopenharmony_ci	if (ret >= 0) {
18568c2ecf20Sopenharmony_ci		if (val == 0 || val == 2 || val == 3) {
18578c2ecf20Sopenharmony_ci			pdata->dismod = DISMOD_VAL(val);
18588c2ecf20Sopenharmony_ci		} else {
18598c2ecf20Sopenharmony_ci			dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
18608c2ecf20Sopenharmony_ci			pdata->dismod = DISMOD_LOW;
18618c2ecf20Sopenharmony_ci		}
18628c2ecf20Sopenharmony_ci	} else {
18638c2ecf20Sopenharmony_ci		pdata->dismod = DISMOD_LOW;
18648c2ecf20Sopenharmony_ci	}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	return  pdata;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_cinodata:
18698c2ecf20Sopenharmony_ci	if (ret < 0) {
18708c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Error populating platform data, err %d\n",
18718c2ecf20Sopenharmony_ci			ret);
18728c2ecf20Sopenharmony_ci		pdata = NULL;
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci	return  pdata;
18758c2ecf20Sopenharmony_ci}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cienum {
18788c2ecf20Sopenharmony_ci	PCM_EDMA,
18798c2ecf20Sopenharmony_ci	PCM_SDMA,
18808c2ecf20Sopenharmony_ci	PCM_UDMA,
18818c2ecf20Sopenharmony_ci};
18828c2ecf20Sopenharmony_cistatic const char *sdma_prefix = "ti,omap";
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_cistatic int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
18858c2ecf20Sopenharmony_ci{
18868c2ecf20Sopenharmony_ci	struct dma_chan *chan;
18878c2ecf20Sopenharmony_ci	const char *tmp;
18888c2ecf20Sopenharmony_ci	int ret = PCM_EDMA;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (!mcasp->dev->of_node)
18918c2ecf20Sopenharmony_ci		return PCM_EDMA;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
18948c2ecf20Sopenharmony_ci	chan = dma_request_chan(mcasp->dev, tmp);
18958c2ecf20Sopenharmony_ci	if (IS_ERR(chan)) {
18968c2ecf20Sopenharmony_ci		if (PTR_ERR(chan) != -EPROBE_DEFER)
18978c2ecf20Sopenharmony_ci			dev_err(mcasp->dev,
18988c2ecf20Sopenharmony_ci				"Can't verify DMA configuration (%ld)\n",
18998c2ecf20Sopenharmony_ci				PTR_ERR(chan));
19008c2ecf20Sopenharmony_ci		return PTR_ERR(chan);
19018c2ecf20Sopenharmony_ci	}
19028c2ecf20Sopenharmony_ci	if (WARN_ON(!chan->device || !chan->device->dev)) {
19038c2ecf20Sopenharmony_ci		dma_release_channel(chan);
19048c2ecf20Sopenharmony_ci		return -EINVAL;
19058c2ecf20Sopenharmony_ci	}
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	if (chan->device->dev->of_node)
19088c2ecf20Sopenharmony_ci		ret = of_property_read_string(chan->device->dev->of_node,
19098c2ecf20Sopenharmony_ci					      "compatible", &tmp);
19108c2ecf20Sopenharmony_ci	else
19118c2ecf20Sopenharmony_ci		dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	dma_release_channel(chan);
19148c2ecf20Sopenharmony_ci	if (ret)
19158c2ecf20Sopenharmony_ci		return ret;
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
19188c2ecf20Sopenharmony_ci	if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
19198c2ecf20Sopenharmony_ci		return PCM_SDMA;
19208c2ecf20Sopenharmony_ci	else if (strstr(tmp, "udmap"))
19218c2ecf20Sopenharmony_ci		return PCM_UDMA;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	return PCM_EDMA;
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata)
19278c2ecf20Sopenharmony_ci{
19288c2ecf20Sopenharmony_ci	int i;
19298c2ecf20Sopenharmony_ci	u32 offset = 0;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	if (pdata->version != MCASP_VERSION_4)
19328c2ecf20Sopenharmony_ci		return pdata->tx_dma_offset;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	for (i = 0; i < pdata->num_serializer; i++) {
19358c2ecf20Sopenharmony_ci		if (pdata->serial_dir[i] == TX_MODE) {
19368c2ecf20Sopenharmony_ci			if (!offset) {
19378c2ecf20Sopenharmony_ci				offset = DAVINCI_MCASP_TXBUF_REG(i);
19388c2ecf20Sopenharmony_ci			} else {
19398c2ecf20Sopenharmony_ci				pr_err("%s: Only one serializer allowed!\n",
19408c2ecf20Sopenharmony_ci				       __func__);
19418c2ecf20Sopenharmony_ci				break;
19428c2ecf20Sopenharmony_ci			}
19438c2ecf20Sopenharmony_ci		}
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	return offset;
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
19508c2ecf20Sopenharmony_ci{
19518c2ecf20Sopenharmony_ci	int i;
19528c2ecf20Sopenharmony_ci	u32 offset = 0;
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	if (pdata->version != MCASP_VERSION_4)
19558c2ecf20Sopenharmony_ci		return pdata->rx_dma_offset;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	for (i = 0; i < pdata->num_serializer; i++) {
19588c2ecf20Sopenharmony_ci		if (pdata->serial_dir[i] == RX_MODE) {
19598c2ecf20Sopenharmony_ci			if (!offset) {
19608c2ecf20Sopenharmony_ci				offset = DAVINCI_MCASP_RXBUF_REG(i);
19618c2ecf20Sopenharmony_ci			} else {
19628c2ecf20Sopenharmony_ci				pr_err("%s: Only one serializer allowed!\n",
19638c2ecf20Sopenharmony_ci				       __func__);
19648c2ecf20Sopenharmony_ci				break;
19658c2ecf20Sopenharmony_ci			}
19668c2ecf20Sopenharmony_ci		}
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	return offset;
19708c2ecf20Sopenharmony_ci}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB
19738c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	if (mcasp->num_serializer && offset < mcasp->num_serializer &&
19788c2ecf20Sopenharmony_ci	    mcasp->serial_dir[offset] != INACTIVE_MODE) {
19798c2ecf20Sopenharmony_ci		dev_err(mcasp->dev, "AXR%u pin is  used for audio\n", offset);
19808c2ecf20Sopenharmony_ci		return -EBUSY;
19818c2ecf20Sopenharmony_ci	}
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	/* Do not change the PIN yet */
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	return pm_runtime_get_sync(mcasp->dev);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_cistatic void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
19898c2ecf20Sopenharmony_ci{
19908c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	/* Set the direction to input */
19938c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/* Set the pin as McASP pin */
19968c2ecf20Sopenharmony_ci	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	pm_runtime_put_sync(mcasp->dev);
19998c2ecf20Sopenharmony_ci}
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip,
20028c2ecf20Sopenharmony_ci					    unsigned offset, int value)
20038c2ecf20Sopenharmony_ci{
20048c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
20058c2ecf20Sopenharmony_ci	u32 val;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	if (value)
20088c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
20098c2ecf20Sopenharmony_ci	else
20108c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
20138c2ecf20Sopenharmony_ci	if (!(val & BIT(offset))) {
20148c2ecf20Sopenharmony_ci		/* Set the pin as GPIO pin */
20158c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci		/* Set the direction to output */
20188c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
20198c2ecf20Sopenharmony_ci	}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	return 0;
20228c2ecf20Sopenharmony_ci}
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_cistatic void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset,
20258c2ecf20Sopenharmony_ci				  int value)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	if (value)
20308c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
20318c2ecf20Sopenharmony_ci	else
20328c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip,
20368c2ecf20Sopenharmony_ci					   unsigned offset)
20378c2ecf20Sopenharmony_ci{
20388c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
20398c2ecf20Sopenharmony_ci	u32 val;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
20428c2ecf20Sopenharmony_ci	if (!(val & BIT(offset))) {
20438c2ecf20Sopenharmony_ci		/* Set the direction to input */
20448c2ecf20Sopenharmony_ci		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci		/* Set the pin as GPIO pin */
20478c2ecf20Sopenharmony_ci		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
20488c2ecf20Sopenharmony_ci	}
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	return 0;
20518c2ecf20Sopenharmony_ci}
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
20568c2ecf20Sopenharmony_ci	u32 val;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG);
20598c2ecf20Sopenharmony_ci	if (val & BIT(offset))
20608c2ecf20Sopenharmony_ci		return 1;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	return 0;
20638c2ecf20Sopenharmony_ci}
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip,
20668c2ecf20Sopenharmony_ci					    unsigned offset)
20678c2ecf20Sopenharmony_ci{
20688c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
20698c2ecf20Sopenharmony_ci	u32 val;
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
20728c2ecf20Sopenharmony_ci	if (val & BIT(offset))
20738c2ecf20Sopenharmony_ci		return 0;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	return 1;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_cistatic const struct gpio_chip davinci_mcasp_template_chip = {
20798c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
20808c2ecf20Sopenharmony_ci	.request		= davinci_mcasp_gpio_request,
20818c2ecf20Sopenharmony_ci	.free			= davinci_mcasp_gpio_free,
20828c2ecf20Sopenharmony_ci	.direction_output	= davinci_mcasp_gpio_direction_out,
20838c2ecf20Sopenharmony_ci	.set			= davinci_mcasp_gpio_set,
20848c2ecf20Sopenharmony_ci	.direction_input	= davinci_mcasp_gpio_direction_in,
20858c2ecf20Sopenharmony_ci	.get			= davinci_mcasp_gpio_get,
20868c2ecf20Sopenharmony_ci	.get_direction		= davinci_mcasp_gpio_get_direction,
20878c2ecf20Sopenharmony_ci	.base			= -1,
20888c2ecf20Sopenharmony_ci	.ngpio			= 32,
20898c2ecf20Sopenharmony_ci};
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_cistatic int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
20928c2ecf20Sopenharmony_ci{
20938c2ecf20Sopenharmony_ci	if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
20948c2ecf20Sopenharmony_ci		return 0;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	mcasp->gpio_chip = davinci_mcasp_template_chip;
20978c2ecf20Sopenharmony_ci	mcasp->gpio_chip.label = dev_name(mcasp->dev);
20988c2ecf20Sopenharmony_ci	mcasp->gpio_chip.parent = mcasp->dev;
20998c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO
21008c2ecf20Sopenharmony_ci	mcasp->gpio_chip.of_node = mcasp->dev->of_node;
21018c2ecf20Sopenharmony_ci#endif
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp);
21048c2ecf20Sopenharmony_ci}
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci#else /* CONFIG_GPIOLIB */
21078c2ecf20Sopenharmony_cistatic inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
21088c2ecf20Sopenharmony_ci{
21098c2ecf20Sopenharmony_ci	return 0;
21108c2ecf20Sopenharmony_ci}
21118c2ecf20Sopenharmony_ci#endif /* CONFIG_GPIOLIB */
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_cistatic int davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp)
21148c2ecf20Sopenharmony_ci{
21158c2ecf20Sopenharmony_ci	struct device_node *np = mcasp->dev->of_node;
21168c2ecf20Sopenharmony_ci	int ret;
21178c2ecf20Sopenharmony_ci	u32 val;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	if (!np)
21208c2ecf20Sopenharmony_ci		return 0;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "auxclk-fs-ratio", &val);
21238c2ecf20Sopenharmony_ci	if (ret >= 0)
21248c2ecf20Sopenharmony_ci		mcasp->auxclk_fs_ratio = val;
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	return 0;
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_cistatic int davinci_mcasp_probe(struct platform_device *pdev)
21308c2ecf20Sopenharmony_ci{
21318c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data;
21328c2ecf20Sopenharmony_ci	struct resource *mem, *res, *dat;
21338c2ecf20Sopenharmony_ci	struct davinci_mcasp_pdata *pdata;
21348c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp;
21358c2ecf20Sopenharmony_ci	char *irq_name;
21368c2ecf20Sopenharmony_ci	int *dma;
21378c2ecf20Sopenharmony_ci	int irq;
21388c2ecf20Sopenharmony_ci	int ret;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
21418c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No platform data supplied\n");
21428c2ecf20Sopenharmony_ci		return -EINVAL;
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
21468c2ecf20Sopenharmony_ci			   GFP_KERNEL);
21478c2ecf20Sopenharmony_ci	if (!mcasp)
21488c2ecf20Sopenharmony_ci		return	-ENOMEM;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	pdata = davinci_mcasp_set_pdata_from_of(pdev);
21518c2ecf20Sopenharmony_ci	if (!pdata) {
21528c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no platform data\n");
21538c2ecf20Sopenharmony_ci		return -EINVAL;
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
21578c2ecf20Sopenharmony_ci	if (!mem) {
21588c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
21598c2ecf20Sopenharmony_ci			 "\"mpu\" mem resource not found, using index 0\n");
21608c2ecf20Sopenharmony_ci		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
21618c2ecf20Sopenharmony_ci		if (!mem) {
21628c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "no mem resource?\n");
21638c2ecf20Sopenharmony_ci			return -ENODEV;
21648c2ecf20Sopenharmony_ci		}
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
21688c2ecf20Sopenharmony_ci	if (IS_ERR(mcasp->base))
21698c2ecf20Sopenharmony_ci		return PTR_ERR(mcasp->base);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	mcasp->op_mode = pdata->op_mode;
21748c2ecf20Sopenharmony_ci	/* sanity check for tdm slots parameter */
21758c2ecf20Sopenharmony_ci	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
21768c2ecf20Sopenharmony_ci		if (pdata->tdm_slots < 2) {
21778c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
21788c2ecf20Sopenharmony_ci				pdata->tdm_slots);
21798c2ecf20Sopenharmony_ci			mcasp->tdm_slots = 2;
21808c2ecf20Sopenharmony_ci		} else if (pdata->tdm_slots > 32) {
21818c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "invalid tdm slots: %d\n",
21828c2ecf20Sopenharmony_ci				pdata->tdm_slots);
21838c2ecf20Sopenharmony_ci			mcasp->tdm_slots = 32;
21848c2ecf20Sopenharmony_ci		} else {
21858c2ecf20Sopenharmony_ci			mcasp->tdm_slots = pdata->tdm_slots;
21868c2ecf20Sopenharmony_ci		}
21878c2ecf20Sopenharmony_ci	}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	mcasp->num_serializer = pdata->num_serializer;
21908c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
21918c2ecf20Sopenharmony_ci	mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
21928c2ecf20Sopenharmony_ci					mcasp->num_serializer, sizeof(u32),
21938c2ecf20Sopenharmony_ci					GFP_KERNEL);
21948c2ecf20Sopenharmony_ci	if (!mcasp->context.xrsr_regs) {
21958c2ecf20Sopenharmony_ci		ret = -ENOMEM;
21968c2ecf20Sopenharmony_ci		goto err;
21978c2ecf20Sopenharmony_ci	}
21988c2ecf20Sopenharmony_ci#endif
21998c2ecf20Sopenharmony_ci	mcasp->serial_dir = pdata->serial_dir;
22008c2ecf20Sopenharmony_ci	mcasp->version = pdata->version;
22018c2ecf20Sopenharmony_ci	mcasp->txnumevt = pdata->txnumevt;
22028c2ecf20Sopenharmony_ci	mcasp->rxnumevt = pdata->rxnumevt;
22038c2ecf20Sopenharmony_ci	mcasp->dismod = pdata->dismod;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	mcasp->dev = &pdev->dev;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	irq = platform_get_irq_byname(pdev, "common");
22088c2ecf20Sopenharmony_ci	if (irq >= 0) {
22098c2ecf20Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
22108c2ecf20Sopenharmony_ci					  dev_name(&pdev->dev));
22118c2ecf20Sopenharmony_ci		if (!irq_name) {
22128c2ecf20Sopenharmony_ci			ret = -ENOMEM;
22138c2ecf20Sopenharmony_ci			goto err;
22148c2ecf20Sopenharmony_ci		}
22158c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
22168c2ecf20Sopenharmony_ci						davinci_mcasp_common_irq_handler,
22178c2ecf20Sopenharmony_ci						IRQF_ONESHOT | IRQF_SHARED,
22188c2ecf20Sopenharmony_ci						irq_name, mcasp);
22198c2ecf20Sopenharmony_ci		if (ret) {
22208c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "common IRQ request failed\n");
22218c2ecf20Sopenharmony_ci			goto err;
22228c2ecf20Sopenharmony_ci		}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
22258c2ecf20Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
22268c2ecf20Sopenharmony_ci	}
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	irq = platform_get_irq_byname(pdev, "rx");
22298c2ecf20Sopenharmony_ci	if (irq >= 0) {
22308c2ecf20Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
22318c2ecf20Sopenharmony_ci					  dev_name(&pdev->dev));
22328c2ecf20Sopenharmony_ci		if (!irq_name) {
22338c2ecf20Sopenharmony_ci			ret = -ENOMEM;
22348c2ecf20Sopenharmony_ci			goto err;
22358c2ecf20Sopenharmony_ci		}
22368c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
22378c2ecf20Sopenharmony_ci						davinci_mcasp_rx_irq_handler,
22388c2ecf20Sopenharmony_ci						IRQF_ONESHOT, irq_name, mcasp);
22398c2ecf20Sopenharmony_ci		if (ret) {
22408c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "RX IRQ request failed\n");
22418c2ecf20Sopenharmony_ci			goto err;
22428c2ecf20Sopenharmony_ci		}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	irq = platform_get_irq_byname(pdev, "tx");
22488c2ecf20Sopenharmony_ci	if (irq >= 0) {
22498c2ecf20Sopenharmony_ci		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
22508c2ecf20Sopenharmony_ci					  dev_name(&pdev->dev));
22518c2ecf20Sopenharmony_ci		if (!irq_name) {
22528c2ecf20Sopenharmony_ci			ret = -ENOMEM;
22538c2ecf20Sopenharmony_ci			goto err;
22548c2ecf20Sopenharmony_ci		}
22558c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
22568c2ecf20Sopenharmony_ci						davinci_mcasp_tx_irq_handler,
22578c2ecf20Sopenharmony_ci						IRQF_ONESHOT, irq_name, mcasp);
22588c2ecf20Sopenharmony_ci		if (ret) {
22598c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "TX IRQ request failed\n");
22608c2ecf20Sopenharmony_ci			goto err;
22618c2ecf20Sopenharmony_ci		}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
22648c2ecf20Sopenharmony_ci	}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
22678c2ecf20Sopenharmony_ci	if (dat)
22688c2ecf20Sopenharmony_ci		mcasp->dat_port = true;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
22718c2ecf20Sopenharmony_ci	if (dat)
22728c2ecf20Sopenharmony_ci		dma_data->addr = dat->start;
22738c2ecf20Sopenharmony_ci	else
22748c2ecf20Sopenharmony_ci		dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
22778c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
22788c2ecf20Sopenharmony_ci	if (res)
22798c2ecf20Sopenharmony_ci		*dma = res->start;
22808c2ecf20Sopenharmony_ci	else
22818c2ecf20Sopenharmony_ci		*dma = pdata->tx_dma_channel;
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	/* dmaengine filter data for DT and non-DT boot */
22848c2ecf20Sopenharmony_ci	if (pdev->dev.of_node)
22858c2ecf20Sopenharmony_ci		dma_data->filter_data = "tx";
22868c2ecf20Sopenharmony_ci	else
22878c2ecf20Sopenharmony_ci		dma_data->filter_data = dma;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	/* RX is not valid in DIT mode */
22908c2ecf20Sopenharmony_ci	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
22918c2ecf20Sopenharmony_ci		dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
22928c2ecf20Sopenharmony_ci		if (dat)
22938c2ecf20Sopenharmony_ci			dma_data->addr = dat->start;
22948c2ecf20Sopenharmony_ci		else
22958c2ecf20Sopenharmony_ci			dma_data->addr =
22968c2ecf20Sopenharmony_ci				mem->start + davinci_mcasp_rxdma_offset(pdata);
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci		dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
22998c2ecf20Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
23008c2ecf20Sopenharmony_ci		if (res)
23018c2ecf20Sopenharmony_ci			*dma = res->start;
23028c2ecf20Sopenharmony_ci		else
23038c2ecf20Sopenharmony_ci			*dma = pdata->rx_dma_channel;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci		/* dmaengine filter data for DT and non-DT boot */
23068c2ecf20Sopenharmony_ci		if (pdev->dev.of_node)
23078c2ecf20Sopenharmony_ci			dma_data->filter_data = "rx";
23088c2ecf20Sopenharmony_ci		else
23098c2ecf20Sopenharmony_ci			dma_data->filter_data = dma;
23108c2ecf20Sopenharmony_ci	}
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	if (mcasp->version < MCASP_VERSION_3) {
23138c2ecf20Sopenharmony_ci		mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
23148c2ecf20Sopenharmony_ci		/* dma_params->dma_addr is pointing to the data port address */
23158c2ecf20Sopenharmony_ci		mcasp->dat_port = true;
23168c2ecf20Sopenharmony_ci	} else {
23178c2ecf20Sopenharmony_ci		mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
23188c2ecf20Sopenharmony_ci	}
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	/* Allocate memory for long enough list for all possible
23218c2ecf20Sopenharmony_ci	 * scenarios. Maximum number tdm slots is 32 and there cannot
23228c2ecf20Sopenharmony_ci	 * be more serializers than given in the configuration.  The
23238c2ecf20Sopenharmony_ci	 * serializer directions could be taken into account, but it
23248c2ecf20Sopenharmony_ci	 * would make code much more complex and save only couple of
23258c2ecf20Sopenharmony_ci	 * bytes.
23268c2ecf20Sopenharmony_ci	 */
23278c2ecf20Sopenharmony_ci	mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
23288c2ecf20Sopenharmony_ci		devm_kcalloc(mcasp->dev,
23298c2ecf20Sopenharmony_ci			     32 + mcasp->num_serializer - 1,
23308c2ecf20Sopenharmony_ci			     sizeof(unsigned int),
23318c2ecf20Sopenharmony_ci			     GFP_KERNEL);
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
23348c2ecf20Sopenharmony_ci		devm_kcalloc(mcasp->dev,
23358c2ecf20Sopenharmony_ci			     32 + mcasp->num_serializer - 1,
23368c2ecf20Sopenharmony_ci			     sizeof(unsigned int),
23378c2ecf20Sopenharmony_ci			     GFP_KERNEL);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
23408c2ecf20Sopenharmony_ci	    !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
23418c2ecf20Sopenharmony_ci		ret = -ENOMEM;
23428c2ecf20Sopenharmony_ci		goto err;
23438c2ecf20Sopenharmony_ci	}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	ret = davinci_mcasp_set_ch_constraints(mcasp);
23468c2ecf20Sopenharmony_ci	if (ret)
23478c2ecf20Sopenharmony_ci		goto err;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	dev_set_drvdata(&pdev->dev, mcasp);
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	mcasp_reparent_fck(pdev);
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	/* All PINS as McASP */
23548c2ecf20Sopenharmony_ci	pm_runtime_get_sync(mcasp->dev);
23558c2ecf20Sopenharmony_ci	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
23568c2ecf20Sopenharmony_ci	pm_runtime_put(mcasp->dev);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	ret = davinci_mcasp_init_gpiochip(mcasp);
23598c2ecf20Sopenharmony_ci	if (ret)
23608c2ecf20Sopenharmony_ci		goto err;
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci	ret = davinci_mcasp_get_dt_params(mcasp);
23638c2ecf20Sopenharmony_ci	if (ret)
23648c2ecf20Sopenharmony_ci		return -EINVAL;
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev,
23678c2ecf20Sopenharmony_ci					&davinci_mcasp_component,
23688c2ecf20Sopenharmony_ci					&davinci_mcasp_dai[pdata->op_mode], 1);
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	if (ret != 0)
23718c2ecf20Sopenharmony_ci		goto err;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	ret = davinci_mcasp_get_dma_type(mcasp);
23748c2ecf20Sopenharmony_ci	switch (ret) {
23758c2ecf20Sopenharmony_ci	case PCM_EDMA:
23768c2ecf20Sopenharmony_ci		ret = edma_pcm_platform_register(&pdev->dev);
23778c2ecf20Sopenharmony_ci		break;
23788c2ecf20Sopenharmony_ci	case PCM_SDMA:
23798c2ecf20Sopenharmony_ci		ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
23808c2ecf20Sopenharmony_ci		break;
23818c2ecf20Sopenharmony_ci	case PCM_UDMA:
23828c2ecf20Sopenharmony_ci		ret = udma_pcm_platform_register(&pdev->dev);
23838c2ecf20Sopenharmony_ci		break;
23848c2ecf20Sopenharmony_ci	default:
23858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
23868c2ecf20Sopenharmony_ci	case -EPROBE_DEFER:
23878c2ecf20Sopenharmony_ci		goto err;
23888c2ecf20Sopenharmony_ci		break;
23898c2ecf20Sopenharmony_ci	}
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	if (ret) {
23928c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
23938c2ecf20Sopenharmony_ci		goto err;
23948c2ecf20Sopenharmony_ci	}
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	return 0;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_cierr:
23998c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
24008c2ecf20Sopenharmony_ci	return ret;
24018c2ecf20Sopenharmony_ci}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_cistatic int davinci_mcasp_remove(struct platform_device *pdev)
24048c2ecf20Sopenharmony_ci{
24058c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	return 0;
24088c2ecf20Sopenharmony_ci}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
24118c2ecf20Sopenharmony_cistatic int davinci_mcasp_runtime_suspend(struct device *dev)
24128c2ecf20Sopenharmony_ci{
24138c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
24148c2ecf20Sopenharmony_ci	struct davinci_mcasp_context *context = &mcasp->context;
24158c2ecf20Sopenharmony_ci	u32 reg;
24168c2ecf20Sopenharmony_ci	int i;
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
24198c2ecf20Sopenharmony_ci		context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	if (mcasp->txnumevt) {
24228c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
24238c2ecf20Sopenharmony_ci		context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
24248c2ecf20Sopenharmony_ci	}
24258c2ecf20Sopenharmony_ci	if (mcasp->rxnumevt) {
24268c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
24278c2ecf20Sopenharmony_ci		context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
24288c2ecf20Sopenharmony_ci	}
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
24318c2ecf20Sopenharmony_ci		context->xrsr_regs[i] = mcasp_get_reg(mcasp,
24328c2ecf20Sopenharmony_ci						DAVINCI_MCASP_XRSRCTL_REG(i));
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	return 0;
24358c2ecf20Sopenharmony_ci}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_cistatic int davinci_mcasp_runtime_resume(struct device *dev)
24388c2ecf20Sopenharmony_ci{
24398c2ecf20Sopenharmony_ci	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
24408c2ecf20Sopenharmony_ci	struct davinci_mcasp_context *context = &mcasp->context;
24418c2ecf20Sopenharmony_ci	u32 reg;
24428c2ecf20Sopenharmony_ci	int i;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
24458c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	if (mcasp->txnumevt) {
24488c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
24498c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
24508c2ecf20Sopenharmony_ci	}
24518c2ecf20Sopenharmony_ci	if (mcasp->rxnumevt) {
24528c2ecf20Sopenharmony_ci		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
24538c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
24548c2ecf20Sopenharmony_ci	}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	for (i = 0; i < mcasp->num_serializer; i++)
24578c2ecf20Sopenharmony_ci		mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
24588c2ecf20Sopenharmony_ci			      context->xrsr_regs[i]);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	return 0;
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci#endif
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_cistatic const struct dev_pm_ops davinci_mcasp_pm_ops = {
24668c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
24678c2ecf20Sopenharmony_ci			   davinci_mcasp_runtime_resume,
24688c2ecf20Sopenharmony_ci			   NULL)
24698c2ecf20Sopenharmony_ci};
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_cistatic struct platform_driver davinci_mcasp_driver = {
24728c2ecf20Sopenharmony_ci	.probe		= davinci_mcasp_probe,
24738c2ecf20Sopenharmony_ci	.remove		= davinci_mcasp_remove,
24748c2ecf20Sopenharmony_ci	.driver		= {
24758c2ecf20Sopenharmony_ci		.name	= "davinci-mcasp",
24768c2ecf20Sopenharmony_ci		.pm     = &davinci_mcasp_pm_ops,
24778c2ecf20Sopenharmony_ci		.of_match_table = mcasp_dt_ids,
24788c2ecf20Sopenharmony_ci	},
24798c2ecf20Sopenharmony_ci};
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_cimodule_platform_driver(davinci_mcasp_driver);
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steve Chen");
24848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
24858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2486