18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Atmel I2S controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Atmel Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 228c2ecf20Sopenharmony_ci#include <sound/initval.h> 238c2ecf20Sopenharmony_ci#include <sound/soc.h> 248c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MAX_TDM_CHANNELS 8 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * ---- I2S Controller Register map ---- 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR 0x0000 /* Control Register */ 328c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR 0x0004 /* Mode Register */ 338c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR 0x0008 /* Status Register */ 348c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SCR 0x000c /* Status Clear Register */ 358c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SSR 0x0010 /* Status Set Register */ 368c2ecf20Sopenharmony_ci#define ATMEL_I2SC_IER 0x0014 /* Interrupt Enable Register */ 378c2ecf20Sopenharmony_ci#define ATMEL_I2SC_IDR 0x0018 /* Interrupt Disable Register */ 388c2ecf20Sopenharmony_ci#define ATMEL_I2SC_IMR 0x001c /* Interrupt Mask Register */ 398c2ecf20Sopenharmony_ci#define ATMEL_I2SC_RHR 0x0020 /* Receiver Holding Register */ 408c2ecf20Sopenharmony_ci#define ATMEL_I2SC_THR 0x0024 /* Transmitter Holding Register */ 418c2ecf20Sopenharmony_ci#define ATMEL_I2SC_VERSION 0x0028 /* Version Register */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * ---- Control Register (Write-only) ---- 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_RXEN BIT(0) /* Receiver Enable */ 478c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_RXDIS BIT(1) /* Receiver Disable */ 488c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_CKEN BIT(2) /* Clock Enable */ 498c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_CKDIS BIT(3) /* Clock Disable */ 508c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_TXEN BIT(4) /* Transmitter Enable */ 518c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_TXDIS BIT(5) /* Transmitter Disable */ 528c2ecf20Sopenharmony_ci#define ATMEL_I2SC_CR_SWRST BIT(7) /* Software Reset */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * ---- Mode Register (Read/Write) ---- 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_MODE_MASK GENMASK(0, 0) 588c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_MODE_SLAVE (0 << 0) 598c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_MODE_MASTER (1 << 0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_MASK GENMASK(4, 2) 628c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_32_BITS (0 << 2) 638c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_24_BITS (1 << 2) 648c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_20_BITS (2 << 2) 658c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_18_BITS (3 << 2) 668c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_16_BITS (4 << 2) 678c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT (5 << 2) 688c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_8_BITS (6 << 2) 698c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT (7 << 2) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_FORMAT_MASK GENMASK(7, 6) 728c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_FORMAT_I2S (0 << 6) 738c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_FORMAT_LJ (1 << 6) /* Left Justified */ 748c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_FORMAT_TDM (2 << 6) 758c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_FORMAT_TDMLJ (3 << 6) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Left audio samples duplicated to right audio channel */ 788c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_RXMONO BIT(8) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Receiver uses one DMA channel ... */ 818c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_RXDMA_MASK GENMASK(9, 9) 828c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_RXDMA_SINGLE (0 << 9) /* for all audio channels */ 838c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_RXDMA_MULTIPLE (1 << 9) /* per audio channel */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* I2SDO output of I2SC is internally connected to I2SDI input */ 868c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_RXLOOP BIT(10) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Left audio samples duplicated to right audio channel */ 898c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXMONO BIT(12) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* Transmitter uses one DMA channel ... */ 928c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXDMA_MASK GENMASK(13, 13) 938c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXDMA_SINGLE (0 << 13) /* for all audio channels */ 948c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXDME_MULTIPLE (1 << 13) /* per audio channel */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* x sample transmitted when underrun */ 978c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXSAME_MASK GENMASK(14, 14) 988c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXSAME_ZERO (0 << 14) /* Zero sample */ 998c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_TXSAME_PREVIOUS (1 << 14) /* Previous sample */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* Audio Clock to I2SC Master Clock ratio */ 1028c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKDIV_MASK GENMASK(21, 16) 1038c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKDIV(div) \ 1048c2ecf20Sopenharmony_ci (((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Master Clock to fs ratio */ 1078c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKFS_MASK GENMASK(29, 24) 1088c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKFS(fs) \ 1098c2ecf20Sopenharmony_ci (((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* Master Clock mode */ 1128c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKMODE_MASK GENMASK(30, 30) 1138c2ecf20Sopenharmony_ci/* 0: No master clock generated (selected clock drives I2SCK pin) */ 1148c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKMODE_I2SCK (0 << 30) 1158c2ecf20Sopenharmony_ci/* 1: master clock generated (internally generated clock drives I2SMCK pin) */ 1168c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK (1 << 30) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Slot Width */ 1198c2ecf20Sopenharmony_ci/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */ 1208c2ecf20Sopenharmony_ci/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */ 1218c2ecf20Sopenharmony_ci#define ATMEL_I2SC_MR_IWS BIT(31) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * ---- Status Registers ---- 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_RXEN BIT(0) /* Receiver Enabled */ 1278c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_RXRDY BIT(1) /* Receive Ready */ 1288c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_RXOR BIT(2) /* Receive Overrun */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_TXEN BIT(4) /* Transmitter Enabled */ 1318c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_TXRDY BIT(5) /* Transmit Ready */ 1328c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_TXUR BIT(6) /* Transmit Underrun */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* Receive Overrun Channel */ 1358c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_RXORCH_MASK GENMASK(15, 8) 1368c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_RXORCH(ch) (1 << (((ch) & 0x7) + 8)) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Transmit Underrun Channel */ 1398c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_TXURCH_MASK GENMASK(27, 20) 1408c2ecf20Sopenharmony_ci#define ATMEL_I2SC_SR_TXURCH(ch) (1 << (((ch) & 0x7) + 20)) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * ---- Interrupt Enable/Disable/Mask Registers ---- 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci#define ATMEL_I2SC_INT_RXRDY ATMEL_I2SC_SR_RXRDY 1468c2ecf20Sopenharmony_ci#define ATMEL_I2SC_INT_RXOR ATMEL_I2SC_SR_RXOR 1478c2ecf20Sopenharmony_ci#define ATMEL_I2SC_INT_TXRDY ATMEL_I2SC_SR_TXRDY 1488c2ecf20Sopenharmony_ci#define ATMEL_I2SC_INT_TXUR ATMEL_I2SC_SR_TXUR 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct regmap_config atmel_i2s_regmap_config = { 1518c2ecf20Sopenharmony_ci .reg_bits = 32, 1528c2ecf20Sopenharmony_ci .reg_stride = 4, 1538c2ecf20Sopenharmony_ci .val_bits = 32, 1548c2ecf20Sopenharmony_ci .max_register = ATMEL_I2SC_VERSION, 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistruct atmel_i2s_gck_param { 1588c2ecf20Sopenharmony_ci int fs; 1598c2ecf20Sopenharmony_ci unsigned long mck; 1608c2ecf20Sopenharmony_ci int imckdiv; 1618c2ecf20Sopenharmony_ci int imckfs; 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define I2S_MCK_12M288 12288000UL 1658c2ecf20Sopenharmony_ci#define I2S_MCK_11M2896 11289600UL 1668c2ecf20Sopenharmony_ci#define I2S_MCK_6M144 6144000UL 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */ 1698c2ecf20Sopenharmony_cistatic const struct atmel_i2s_gck_param gck_params[] = { 1708c2ecf20Sopenharmony_ci /* mck = 6.144Mhz */ 1718c2ecf20Sopenharmony_ci { 8000, I2S_MCK_6M144, 1, 47}, /* mck = 768 fs */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* mck = 12.288MHz */ 1748c2ecf20Sopenharmony_ci { 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */ 1758c2ecf20Sopenharmony_ci { 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */ 1768c2ecf20Sopenharmony_ci { 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */ 1778c2ecf20Sopenharmony_ci { 48000, I2S_MCK_12M288, 7, 63}, /* mck = 256 fs */ 1788c2ecf20Sopenharmony_ci { 64000, I2S_MCK_12M288, 7, 47}, /* mck = 192 fs */ 1798c2ecf20Sopenharmony_ci { 96000, I2S_MCK_12M288, 7, 31}, /* mck = 128 fs */ 1808c2ecf20Sopenharmony_ci {192000, I2S_MCK_12M288, 7, 15}, /* mck = 64 fs */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* mck = 11.2896MHz */ 1838c2ecf20Sopenharmony_ci { 11025, I2S_MCK_11M2896, 1, 63}, /* mck = 1024 fs */ 1848c2ecf20Sopenharmony_ci { 22050, I2S_MCK_11M2896, 3, 63}, /* mck = 512 fs */ 1858c2ecf20Sopenharmony_ci { 44100, I2S_MCK_11M2896, 7, 63}, /* mck = 256 fs */ 1868c2ecf20Sopenharmony_ci { 88200, I2S_MCK_11M2896, 7, 31}, /* mck = 128 fs */ 1878c2ecf20Sopenharmony_ci {176400, I2S_MCK_11M2896, 7, 15}, /* mck = 64 fs */ 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistruct atmel_i2s_dev; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistruct atmel_i2s_caps { 1938c2ecf20Sopenharmony_ci int (*mck_init)(struct atmel_i2s_dev *, struct device_node *np); 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistruct atmel_i2s_dev { 1978c2ecf20Sopenharmony_ci struct device *dev; 1988c2ecf20Sopenharmony_ci struct regmap *regmap; 1998c2ecf20Sopenharmony_ci struct clk *pclk; 2008c2ecf20Sopenharmony_ci struct clk *gclk; 2018c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback; 2028c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture; 2038c2ecf20Sopenharmony_ci unsigned int fmt; 2048c2ecf20Sopenharmony_ci const struct atmel_i2s_gck_param *gck_param; 2058c2ecf20Sopenharmony_ci const struct atmel_i2s_caps *caps; 2068c2ecf20Sopenharmony_ci int clk_use_no; 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = dev_id; 2128c2ecf20Sopenharmony_ci unsigned int sr, imr, pending, ch, mask; 2138c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr); 2168c2ecf20Sopenharmony_ci regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr); 2178c2ecf20Sopenharmony_ci pending = sr & imr; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!pending) 2208c2ecf20Sopenharmony_ci return IRQ_NONE; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (pending & ATMEL_I2SC_INT_RXOR) { 2238c2ecf20Sopenharmony_ci mask = ATMEL_I2SC_SR_RXOR; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) { 2268c2ecf20Sopenharmony_ci if (sr & ATMEL_I2SC_SR_RXORCH(ch)) { 2278c2ecf20Sopenharmony_ci mask |= ATMEL_I2SC_SR_RXORCH(ch); 2288c2ecf20Sopenharmony_ci dev_err(dev->dev, 2298c2ecf20Sopenharmony_ci "RX overrun on channel %d\n", ch); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask); 2338c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (pending & ATMEL_I2SC_INT_TXUR) { 2378c2ecf20Sopenharmony_ci mask = ATMEL_I2SC_SR_TXUR; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) { 2408c2ecf20Sopenharmony_ci if (sr & ATMEL_I2SC_SR_TXURCH(ch)) { 2418c2ecf20Sopenharmony_ci mask |= ATMEL_I2SC_SR_TXURCH(ch); 2428c2ecf20Sopenharmony_ci dev_err(dev->dev, 2438c2ecf20Sopenharmony_ci "TX underrun on channel %d\n", ch); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask); 2478c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci#define ATMEL_I2S_RATES SNDRV_PCM_RATE_8000_192000 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#define ATMEL_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 2568c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 2578c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE | \ 2588c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | \ 2598c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 2608c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 2618c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE) 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dev->fmt = fmt; 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int atmel_i2s_prepare(struct snd_pcm_substream *substream, 2728c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); 2758c2ecf20Sopenharmony_ci bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 2768c2ecf20Sopenharmony_ci unsigned int rhr, sr = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (is_playback) { 2798c2ecf20Sopenharmony_ci regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr); 2808c2ecf20Sopenharmony_ci if (sr & ATMEL_I2SC_SR_RXRDY) { 2818c2ecf20Sopenharmony_ci /* 2828c2ecf20Sopenharmony_ci * The RX Ready flag should not be set. However if here, 2838c2ecf20Sopenharmony_ci * we flush (read) the Receive Holding Register to start 2848c2ecf20Sopenharmony_ci * from a clean state. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "RXRDY is set\n"); 2878c2ecf20Sopenharmony_ci regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci int i, best; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!dev->gclk) { 2998c2ecf20Sopenharmony_ci dev_err(dev->dev, "cannot generate the I2S Master Clock\n"); 3008c2ecf20Sopenharmony_ci return -EINVAL; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Find the best possible settings to generate the I2S Master Clock 3058c2ecf20Sopenharmony_ci * from the PLL Audio. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci dev->gck_param = NULL; 3088c2ecf20Sopenharmony_ci best = INT_MAX; 3098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gck_params); ++i) { 3108c2ecf20Sopenharmony_ci const struct atmel_i2s_gck_param *gck_param = &gck_params[i]; 3118c2ecf20Sopenharmony_ci int val = abs(fs - gck_param->fs); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (val < best) { 3148c2ecf20Sopenharmony_ci best = val; 3158c2ecf20Sopenharmony_ci dev->gck_param = gck_param; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int atmel_i2s_hw_params(struct snd_pcm_substream *substream, 3238c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 3248c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); 3278c2ecf20Sopenharmony_ci bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 3288c2ecf20Sopenharmony_ci unsigned int mr = 0, mr_mask; 3298c2ecf20Sopenharmony_ci int ret; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci mr_mask = ATMEL_I2SC_MR_FORMAT_MASK | ATMEL_I2SC_MR_MODE_MASK | 3328c2ecf20Sopenharmony_ci ATMEL_I2SC_MR_DATALENGTH_MASK; 3338c2ecf20Sopenharmony_ci if (is_playback) 3348c2ecf20Sopenharmony_ci mr_mask |= ATMEL_I2SC_MR_TXMONO; 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci mr_mask |= ATMEL_I2SC_MR_RXMONO; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3398c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 3408c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_FORMAT_I2S; 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci default: 3448c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported bus format\n"); 3458c2ecf20Sopenharmony_ci return -EINVAL; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { 3498c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 3508c2ecf20Sopenharmony_ci /* codec is slave, so cpu is master */ 3518c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_MODE_MASTER; 3528c2ecf20Sopenharmony_ci ret = atmel_i2s_get_gck_param(dev, params_rate(params)); 3538c2ecf20Sopenharmony_ci if (ret) 3548c2ecf20Sopenharmony_ci return ret; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 3588c2ecf20Sopenharmony_ci /* codec is master, so cpu is slave */ 3598c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_MODE_SLAVE; 3608c2ecf20Sopenharmony_ci dev->gck_param = NULL; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci default: 3648c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported master/slave mode\n"); 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci switch (params_channels(params)) { 3698c2ecf20Sopenharmony_ci case 1: 3708c2ecf20Sopenharmony_ci if (is_playback) 3718c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_TXMONO; 3728c2ecf20Sopenharmony_ci else 3738c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_RXMONO; 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci case 2: 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci default: 3788c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported number of audio channels\n"); 3798c2ecf20Sopenharmony_ci return -EINVAL; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci switch (params_format(params)) { 3838c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 3848c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 3888c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S18_3LE: 3928c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 3968c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 4008c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS; 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 4048c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 4088c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci default: 4128c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported size/endianness for audio samples\n"); 4138c2ecf20Sopenharmony_ci return -EINVAL; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev, 4208c2ecf20Sopenharmony_ci bool enabled) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci unsigned int mr, mr_mask; 4238c2ecf20Sopenharmony_ci unsigned long gclk_rate; 4248c2ecf20Sopenharmony_ci int ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci mr = 0; 4278c2ecf20Sopenharmony_ci mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK | 4288c2ecf20Sopenharmony_ci ATMEL_I2SC_MR_IMCKFS_MASK | 4298c2ecf20Sopenharmony_ci ATMEL_I2SC_MR_IMCKMODE_MASK); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (!enabled) { 4328c2ecf20Sopenharmony_ci /* Disable the I2S Master Clock generator. */ 4338c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, ATMEL_I2SC_CR, 4348c2ecf20Sopenharmony_ci ATMEL_I2SC_CR_CKDIS); 4358c2ecf20Sopenharmony_ci if (ret) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Reset the I2S Master Clock generator settings. */ 4398c2ecf20Sopenharmony_ci ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, 4408c2ecf20Sopenharmony_ci mr_mask, mr); 4418c2ecf20Sopenharmony_ci if (ret) 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Disable/unprepare the PMC generated clock. */ 4458c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->gclk); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!dev->gck_param) 4518c2ecf20Sopenharmony_ci return -EINVAL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci gclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = clk_set_rate(dev->gclk, gclk_rate); 4568c2ecf20Sopenharmony_ci if (ret) 4578c2ecf20Sopenharmony_ci return ret; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->gclk); 4608c2ecf20Sopenharmony_ci if (ret) 4618c2ecf20Sopenharmony_ci return ret; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Update the Mode Register to generate the I2S Master Clock. */ 4648c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv); 4658c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs); 4668c2ecf20Sopenharmony_ci mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK; 4678c2ecf20Sopenharmony_ci ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr); 4688c2ecf20Sopenharmony_ci if (ret) 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Finally enable the I2S Master Clock generator. */ 4728c2ecf20Sopenharmony_ci return regmap_write(dev->regmap, ATMEL_I2SC_CR, 4738c2ecf20Sopenharmony_ci ATMEL_I2SC_CR_CKEN); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 4778c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); 4808c2ecf20Sopenharmony_ci bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 4818c2ecf20Sopenharmony_ci bool is_master, mck_enabled; 4828c2ecf20Sopenharmony_ci unsigned int cr, mr; 4838c2ecf20Sopenharmony_ci int err; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci switch (cmd) { 4868c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 4878c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 4888c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 4898c2ecf20Sopenharmony_ci cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN; 4908c2ecf20Sopenharmony_ci mck_enabled = true; 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 4938c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 4948c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4958c2ecf20Sopenharmony_ci cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS; 4968c2ecf20Sopenharmony_ci mck_enabled = false; 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci default: 4998c2ecf20Sopenharmony_ci return -EINVAL; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Read the Mode Register to retrieve the master/slave state. */ 5038c2ecf20Sopenharmony_ci err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr); 5048c2ecf20Sopenharmony_ci if (err) 5058c2ecf20Sopenharmony_ci return err; 5068c2ecf20Sopenharmony_ci is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* If master starts, enable the audio clock. */ 5098c2ecf20Sopenharmony_ci if (is_master && mck_enabled) { 5108c2ecf20Sopenharmony_ci if (!dev->clk_use_no) { 5118c2ecf20Sopenharmony_ci err = atmel_i2s_switch_mck_generator(dev, true); 5128c2ecf20Sopenharmony_ci if (err) 5138c2ecf20Sopenharmony_ci return err; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci dev->clk_use_no++; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr); 5198c2ecf20Sopenharmony_ci if (err) 5208c2ecf20Sopenharmony_ci return err; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* If master stops, disable the audio clock. */ 5238c2ecf20Sopenharmony_ci if (is_master && !mck_enabled) { 5248c2ecf20Sopenharmony_ci if (dev->clk_use_no == 1) { 5258c2ecf20Sopenharmony_ci err = atmel_i2s_switch_mck_generator(dev, false); 5268c2ecf20Sopenharmony_ci if (err) 5278c2ecf20Sopenharmony_ci return err; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci dev->clk_use_no--; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return err; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops atmel_i2s_dai_ops = { 5368c2ecf20Sopenharmony_ci .prepare = atmel_i2s_prepare, 5378c2ecf20Sopenharmony_ci .trigger = atmel_i2s_trigger, 5388c2ecf20Sopenharmony_ci .hw_params = atmel_i2s_hw_params, 5398c2ecf20Sopenharmony_ci .set_fmt = atmel_i2s_set_dai_fmt, 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int atmel_i2s_dai_probe(struct snd_soc_dai *dai) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture); 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver atmel_i2s_dai = { 5518c2ecf20Sopenharmony_ci .probe = atmel_i2s_dai_probe, 5528c2ecf20Sopenharmony_ci .playback = { 5538c2ecf20Sopenharmony_ci .channels_min = 1, 5548c2ecf20Sopenharmony_ci .channels_max = 2, 5558c2ecf20Sopenharmony_ci .rates = ATMEL_I2S_RATES, 5568c2ecf20Sopenharmony_ci .formats = ATMEL_I2S_FORMATS, 5578c2ecf20Sopenharmony_ci }, 5588c2ecf20Sopenharmony_ci .capture = { 5598c2ecf20Sopenharmony_ci .channels_min = 1, 5608c2ecf20Sopenharmony_ci .channels_max = 2, 5618c2ecf20Sopenharmony_ci .rates = ATMEL_I2S_RATES, 5628c2ecf20Sopenharmony_ci .formats = ATMEL_I2S_FORMATS, 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci .ops = &atmel_i2s_dai_ops, 5658c2ecf20Sopenharmony_ci .symmetric_rates = 1, 5668c2ecf20Sopenharmony_ci}; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver atmel_i2s_component = { 5698c2ecf20Sopenharmony_ci .name = "atmel-i2s", 5708c2ecf20Sopenharmony_ci}; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev, 5738c2ecf20Sopenharmony_ci struct device_node *np) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct clk *muxclk; 5768c2ecf20Sopenharmony_ci int err; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (!dev->gclk) 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* muxclk is optional, so we return error for probe defer only */ 5828c2ecf20Sopenharmony_ci muxclk = devm_clk_get(dev->dev, "muxclk"); 5838c2ecf20Sopenharmony_ci if (IS_ERR(muxclk)) { 5848c2ecf20Sopenharmony_ci err = PTR_ERR(muxclk); 5858c2ecf20Sopenharmony_ci if (err == -EPROBE_DEFER) 5868c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 5878c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5888c2ecf20Sopenharmony_ci "failed to get the I2S clock control: %d\n", err); 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return clk_set_parent(muxclk, dev->gclk); 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = { 5968c2ecf20Sopenharmony_ci .mck_init = atmel_i2s_sama5d2_mck_init, 5978c2ecf20Sopenharmony_ci}; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_i2s_dt_ids[] = { 6008c2ecf20Sopenharmony_ci { 6018c2ecf20Sopenharmony_ci .compatible = "atmel,sama5d2-i2s", 6028c2ecf20Sopenharmony_ci .data = (void *)&atmel_i2s_sama5d2_caps, 6038c2ecf20Sopenharmony_ci }, 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci { /* sentinel */ } 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int atmel_i2s_probe(struct platform_device *pdev) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 6138c2ecf20Sopenharmony_ci const struct of_device_id *match; 6148c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev; 6158c2ecf20Sopenharmony_ci struct resource *mem; 6168c2ecf20Sopenharmony_ci struct regmap *regmap; 6178c2ecf20Sopenharmony_ci void __iomem *base; 6188c2ecf20Sopenharmony_ci int irq; 6198c2ecf20Sopenharmony_ci int err = -ENXIO; 6208c2ecf20Sopenharmony_ci unsigned int pcm_flags = 0; 6218c2ecf20Sopenharmony_ci unsigned int version; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* Get memory for driver data. */ 6248c2ecf20Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 6258c2ecf20Sopenharmony_ci if (!dev) 6268c2ecf20Sopenharmony_ci return -ENOMEM; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Get hardware capabilities. */ 6298c2ecf20Sopenharmony_ci match = of_match_node(atmel_i2s_dt_ids, np); 6308c2ecf20Sopenharmony_ci if (match) 6318c2ecf20Sopenharmony_ci dev->caps = match->data; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Map I/O registers. */ 6348c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6358c2ecf20Sopenharmony_ci base = devm_ioremap_resource(&pdev->dev, mem); 6368c2ecf20Sopenharmony_ci if (IS_ERR(base)) 6378c2ecf20Sopenharmony_ci return PTR_ERR(base); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci regmap = devm_regmap_init_mmio(&pdev->dev, base, 6408c2ecf20Sopenharmony_ci &atmel_i2s_regmap_config); 6418c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) 6428c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Request IRQ. */ 6458c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 6468c2ecf20Sopenharmony_ci if (irq < 0) 6478c2ecf20Sopenharmony_ci return irq; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0, 6508c2ecf20Sopenharmony_ci dev_name(&pdev->dev), dev); 6518c2ecf20Sopenharmony_ci if (err) 6528c2ecf20Sopenharmony_ci return err; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Get the peripheral clock. */ 6558c2ecf20Sopenharmony_ci dev->pclk = devm_clk_get(&pdev->dev, "pclk"); 6568c2ecf20Sopenharmony_ci if (IS_ERR(dev->pclk)) { 6578c2ecf20Sopenharmony_ci err = PTR_ERR(dev->pclk); 6588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 6598c2ecf20Sopenharmony_ci "failed to get the peripheral clock: %d\n", err); 6608c2ecf20Sopenharmony_ci return err; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Get audio clock to generate the I2S Master Clock (I2S_MCK) */ 6648c2ecf20Sopenharmony_ci dev->gclk = devm_clk_get(&pdev->dev, "gclk"); 6658c2ecf20Sopenharmony_ci if (IS_ERR(dev->gclk)) { 6668c2ecf20Sopenharmony_ci if (PTR_ERR(dev->gclk) == -EPROBE_DEFER) 6678c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6688c2ecf20Sopenharmony_ci /* Master Mode not supported */ 6698c2ecf20Sopenharmony_ci dev->gclk = NULL; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci dev->dev = &pdev->dev; 6728c2ecf20Sopenharmony_ci dev->regmap = regmap; 6738c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* Do hardware specific settings to initialize I2S_MCK generator */ 6768c2ecf20Sopenharmony_ci if (dev->caps && dev->caps->mck_init) { 6778c2ecf20Sopenharmony_ci err = dev->caps->mck_init(dev, np); 6788c2ecf20Sopenharmony_ci if (err) 6798c2ecf20Sopenharmony_ci return err; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* Enable the peripheral clock. */ 6838c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->pclk); 6848c2ecf20Sopenharmony_ci if (err) 6858c2ecf20Sopenharmony_ci return err; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* Get IP version. */ 6888c2ecf20Sopenharmony_ci regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version); 6898c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "hw version: %#x\n", version); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Enable error interrupts. */ 6928c2ecf20Sopenharmony_ci regmap_write(dev->regmap, ATMEL_I2SC_IER, 6938c2ecf20Sopenharmony_ci ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci err = devm_snd_soc_register_component(&pdev->dev, 6968c2ecf20Sopenharmony_ci &atmel_i2s_component, 6978c2ecf20Sopenharmony_ci &atmel_i2s_dai, 1); 6988c2ecf20Sopenharmony_ci if (err) { 6998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register DAI: %d\n", err); 7008c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->pclk); 7018c2ecf20Sopenharmony_ci return err; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* Prepare DMA config. */ 7058c2ecf20Sopenharmony_ci dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR; 7068c2ecf20Sopenharmony_ci dev->playback.maxburst = 1; 7078c2ecf20Sopenharmony_ci dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR; 7088c2ecf20Sopenharmony_ci dev->capture.maxburst = 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (of_property_match_string(np, "dma-names", "rx-tx") == 0) 7118c2ecf20Sopenharmony_ci pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX; 7128c2ecf20Sopenharmony_ci err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags); 7138c2ecf20Sopenharmony_ci if (err) { 7148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register PCM: %d\n", err); 7158c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->pclk); 7168c2ecf20Sopenharmony_ci return err; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int atmel_i2s_remove(struct platform_device *pdev) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct atmel_i2s_dev *dev = platform_get_drvdata(pdev); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->pclk); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic struct platform_driver atmel_i2s_driver = { 7328c2ecf20Sopenharmony_ci .driver = { 7338c2ecf20Sopenharmony_ci .name = "atmel_i2s", 7348c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(atmel_i2s_dt_ids), 7358c2ecf20Sopenharmony_ci }, 7368c2ecf20Sopenharmony_ci .probe = atmel_i2s_probe, 7378c2ecf20Sopenharmony_ci .remove = atmel_i2s_remove, 7388c2ecf20Sopenharmony_ci}; 7398c2ecf20Sopenharmony_cimodule_platform_driver(atmel_i2s_driver); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atmel I2S Controller driver"); 7428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>"); 7438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 744