Commit 458bcee9 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/ux500' into asoc-next

parents 93d4c1e0 eef6473f
...@@ -2236,7 +2236,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -2236,7 +2236,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width) int slots, int slot_width)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
unsigned int val, mask, slots_active; unsigned int val, mask, slot, slots_active;
mask = BIT(AB8500_DIGIFCONF2_IF0WL0) | mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
BIT(AB8500_DIGIFCONF2_IF0WL1); BIT(AB8500_DIGIFCONF2_IF0WL1);
...@@ -2292,27 +2292,34 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -2292,27 +2292,34 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val); snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
/* Setup TDM DA according to active tx slots */ /* Setup TDM DA according to active tx slots */
if (tx_mask & ~0xff)
return -EINVAL;
mask = AB8500_DASLOTCONFX_SLTODAX_MASK; mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
slots_active = hweight32(tx_mask); slots_active = hweight32(tx_mask);
dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__, dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
slots_active); slots_active);
switch (slots_active) { switch (slots_active) {
case 0: case 0:
break; break;
case 1: case 1:
/* Slot 9 -> DA_IN1 & DA_IN3 */ slot = find_first_bit((unsigned long *)&tx_mask, 32);
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11); snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11); snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
break; break;
case 2: case 2:
/* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */ slot = find_first_bit((unsigned long *)&tx_mask, 32);
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9); snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9); snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1);
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
break; break;
case 8: case 8:
dev_dbg(dai->codec->dev, dev_dbg(dai->codec->dev,
...@@ -2327,25 +2334,36 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -2327,25 +2334,36 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
} }
/* Setup TDM AD according to active RX-slots */ /* Setup TDM AD according to active RX-slots */
if (rx_mask & ~0xff)
return -EINVAL;
rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
slots_active = hweight32(rx_mask); slots_active = hweight32(rx_mask);
dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__, dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
slots_active); slots_active);
switch (slots_active) { switch (slots_active) {
case 0: case 0:
break; break;
case 1: case 1:
/* AD_OUT3 -> slot 0 & 1 */ slot = find_first_bit((unsigned long *)&rx_mask, 32);
snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL, snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | AB8500_MASK_SLOT(slot),
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD); AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
break; break;
case 2: case 2:
/* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */ slot = find_first_bit((unsigned long *)&rx_mask, 32);
snd_soc_update_bits(codec,
AB8500_ADSLOTSEL(slot),
AB8500_MASK_SLOT(slot),
AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1);
snd_soc_update_bits(codec, snd_soc_update_bits(codec,
AB8500_ADSLOTSEL1, AB8500_ADSLOTSEL(slot),
AB8500_MASK_ALL, AB8500_MASK_SLOT(slot),
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
break; break;
case 8: case 8:
dev_dbg(dai->codec->dev, dev_dbg(dai->codec->dev,
...@@ -2362,6 +2380,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -2362,6 +2380,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0; return 0;
} }
static const struct snd_soc_dai_ops ab8500_codec_ops = {
.set_fmt = ab8500_codec_set_dai_fmt,
.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
};
static struct snd_soc_dai_driver ab8500_codec_dai[] = { static struct snd_soc_dai_driver ab8500_codec_dai[] = {
{ {
.name = "ab8500-codec-dai.0", .name = "ab8500-codec-dai.0",
...@@ -2373,12 +2396,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = { ...@@ -2373,12 +2396,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
.rates = AB8500_SUPPORTED_RATE, .rates = AB8500_SUPPORTED_RATE,
.formats = AB8500_SUPPORTED_FMT, .formats = AB8500_SUPPORTED_FMT,
}, },
.ops = (struct snd_soc_dai_ops[]) { .ops = &ab8500_codec_ops,
{
.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
.set_fmt = ab8500_codec_set_dai_fmt,
}
},
.symmetric_rates = 1 .symmetric_rates = 1
}, },
{ {
...@@ -2391,12 +2409,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = { ...@@ -2391,12 +2409,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
.rates = AB8500_SUPPORTED_RATE, .rates = AB8500_SUPPORTED_RATE,
.formats = AB8500_SUPPORTED_FMT, .formats = AB8500_SUPPORTED_FMT,
}, },
.ops = (struct snd_soc_dai_ops[]) { .ops = &ab8500_codec_ops,
{
.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
.set_fmt = ab8500_codec_set_dai_fmt,
}
},
.symmetric_rates = 1 .symmetric_rates = 1
} }
}; };
......
...@@ -24,6 +24,13 @@ ...@@ -24,6 +24,13 @@
#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000) #define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) #define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
/* AB8500 interface slot offset definitions */
#define AB8500_AD_DATA0_OFFSET 0
#define AB8500_DA_DATA0_OFFSET 8
#define AB8500_AD_DATA1_OFFSET 16
#define AB8500_DA_DATA1_OFFSET 24
/* AB8500 audio bank (0x0d) register definitions */ /* AB8500 audio bank (0x0d) register definitions */
#define AB8500_POWERUP 0x00 #define AB8500_POWERUP 0x00
...@@ -73,6 +80,7 @@ ...@@ -73,6 +80,7 @@
#define AB8500_ADSLOTSEL14 0x2C #define AB8500_ADSLOTSEL14 0x2C
#define AB8500_ADSLOTSEL15 0x2D #define AB8500_ADSLOTSEL15 0x2D
#define AB8500_ADSLOTSEL16 0x2E #define AB8500_ADSLOTSEL16 0x2E
#define AB8500_ADSLOTSEL(slot) (AB8500_ADSLOTSEL1 + (slot >> 1))
#define AB8500_ADSLOTHIZCTRL1 0x2F #define AB8500_ADSLOTHIZCTRL1 0x2F
#define AB8500_ADSLOTHIZCTRL2 0x30 #define AB8500_ADSLOTHIZCTRL2 0x30
#define AB8500_ADSLOTHIZCTRL3 0x31 #define AB8500_ADSLOTHIZCTRL3 0x31
...@@ -144,6 +152,7 @@ ...@@ -144,6 +152,7 @@
#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1) #define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1)
#define AB8500_MASK_ALL 0xFF #define AB8500_MASK_ALL 0xFF
#define AB8500_MASK_SLOT(slot) ((slot & 1) ? 0xF0 : 0x0F)
#define AB8500_MASK_NONE 0x00 #define AB8500_MASK_NONE 0x00
/* AB8500_POWERUP */ /* AB8500_POWERUP */
...@@ -347,28 +356,21 @@ ...@@ -347,28 +356,21 @@
#define AB8500_DIGIFCONF4_IF1WL0 0 #define AB8500_DIGIFCONF4_IF1WL0 0
/* AB8500_ADSLOTSELX */ /* AB8500_ADSLOTSELX */
#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00 #define AB8500_AD_OUT1 0x0
#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x10 #define AB8500_AD_OUT2 0x1
#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x20 #define AB8500_AD_OUT3 0x2
#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x30 #define AB8500_AD_OUT4 0x3
#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x40 #define AB8500_AD_OUT5 0x4
#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x50 #define AB8500_AD_OUT6 0x5
#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x60 #define AB8500_AD_OUT7 0x6
#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x70 #define AB8500_AD_OUT8 0x7
#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x80 #define AB8500_ZEROES 0x8
#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0xF0 #define AB8500_TRISTATE 0xF
#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00
#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x01
#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x02
#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x03
#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x04
#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x05
#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x06
#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x07
#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN 0x08
#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN 0x0F
#define AB8500_ADSLOTSELX_EVEN_SHIFT 0 #define AB8500_ADSLOTSELX_EVEN_SHIFT 0
#define AB8500_ADSLOTSELX_ODD_SHIFT 4 #define AB8500_ADSLOTSELX_ODD_SHIFT 4
#define AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(out, slot) \
((out) << (((slot) & 1) ? \
AB8500_ADSLOTSELX_ODD_SHIFT : AB8500_ADSLOTSELX_EVEN_SHIFT))
/* AB8500_ADSLOTHIZCTRL1 */ /* AB8500_ADSLOTHIZCTRL1 */
/* AB8500_ADSLOTHIZCTRL2 */ /* AB8500_ADSLOTHIZCTRL2 */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mutex.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
#include "ux500_pcm.h" #include "ux500_pcm.h"
#include "ux500_msp_dai.h" #include "ux500_msp_dai.h"
#include "mop500_ab8500.h"
#include "../codecs/ab8500-codec.h" #include "../codecs/ab8500-codec.h"
#define TX_SLOT_MONO 0x0008 #define TX_SLOT_MONO 0x0008
...@@ -43,6 +45,12 @@ ...@@ -43,6 +45,12 @@
static unsigned int tx_slots = DEF_TX_SLOTS; static unsigned int tx_slots = DEF_TX_SLOTS;
static unsigned int rx_slots = DEF_RX_SLOTS; static unsigned int rx_slots = DEF_RX_SLOTS;
/* Configuration consistency parameters */
static DEFINE_MUTEX(mop500_ab8500_params_lock);
static unsigned long mop500_ab8500_usage;
static int mop500_ab8500_rate;
static int mop500_ab8500_channels;
/* Clocks */ /* Clocks */
static const char * const enum_mclk[] = { static const char * const enum_mclk[] = {
"SYSCLK", "SYSCLK",
...@@ -230,6 +238,21 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, ...@@ -230,6 +238,21 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
substream->name, substream->name,
substream->number); substream->number);
/* Ensure configuration consistency between DAIs */
mutex_lock(&mop500_ab8500_params_lock);
if (mop500_ab8500_usage) {
if (mop500_ab8500_rate != params_rate(params) ||
mop500_ab8500_channels != params_channels(params)) {
mutex_unlock(&mop500_ab8500_params_lock);
return -EBUSY;
}
} else {
mop500_ab8500_rate = params_rate(params);
mop500_ab8500_channels = params_channels(params);
}
__set_bit(cpu_dai->id, &mop500_ab8500_usage);
mutex_unlock(&mop500_ab8500_params_lock);
channels = params_channels(params); channels = params_channels(params);
switch (params_format(params)) { switch (params_format(params)) {
...@@ -328,9 +351,22 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, ...@@ -328,9 +351,22 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
mutex_lock(&mop500_ab8500_params_lock);
__clear_bit(cpu_dai->id, &mop500_ab8500_usage);
mutex_unlock(&mop500_ab8500_params_lock);
return 0;
}
struct snd_soc_ops mop500_ab8500_ops[] = { struct snd_soc_ops mop500_ab8500_ops[] = {
{ {
.hw_params = mop500_ab8500_hw_params, .hw_params = mop500_ab8500_hw_params,
.hw_free = mop500_ab8500_hw_free,
.startup = mop500_ab8500_startup, .startup = mop500_ab8500_startup,
.shutdown = mop500_ab8500_shutdown, .shutdown = mop500_ab8500_shutdown,
} }
......
...@@ -658,14 +658,11 @@ static int ux500_msp_dai_probe(struct snd_soc_dai *dai) ...@@ -658,14 +658,11 @@ static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
{ {
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx; dai->playback_dma_data = &drvdata->msp->playback_dma_data;
drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx; dai->capture_dma_data = &drvdata->msp->capture_dma_data;
dai->playback_dma_data = &drvdata->playback_dma_data; drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
dai->capture_dma_data = &drvdata->capture_dma_data; drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
drvdata->playback_dma_data.data_size = drvdata->slot_width;
drvdata->capture_dma_data.data_size = drvdata->slot_width;
return 0; return 0;
} }
......
...@@ -51,15 +51,11 @@ enum ux500_msp_clock_id { ...@@ -51,15 +51,11 @@ enum ux500_msp_clock_id {
struct ux500_msp_i2s_drvdata { struct ux500_msp_i2s_drvdata {
struct ux500_msp *msp; struct ux500_msp *msp;
struct regulator *reg_vape; struct regulator *reg_vape;
struct ux500_msp_dma_params playback_dma_data;
struct ux500_msp_dma_params capture_dma_data;
unsigned int fmt; unsigned int fmt;
unsigned int tx_mask; unsigned int tx_mask;
unsigned int rx_mask; unsigned int rx_mask;
int slots; int slots;
int slot_width; int slot_width;
u8 configured;
int data_delay;
/* Clocks */ /* Clocks */
unsigned int master_clk; unsigned int master_clk;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -26,9 +25,6 @@ ...@@ -26,9 +25,6 @@
#include "ux500_msp_i2s.h" #include "ux500_msp_i2s.h"
/* MSP1/3 Tx/Rx usage protection */
static DEFINE_SPINLOCK(msp_rxtx_lock);
/* Protocol desciptors */ /* Protocol desciptors */
static const struct msp_protdesc prot_descs[] = { static const struct msp_protdesc prot_descs[] = {
{ /* I2S */ { /* I2S */
...@@ -356,24 +352,8 @@ static int configure_multichannel(struct ux500_msp *msp, ...@@ -356,24 +352,8 @@ static int configure_multichannel(struct ux500_msp *msp,
static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
{ {
int status = 0, retval = 0; int status = 0;
u32 reg_val_DMACR, reg_val_GCR; u32 reg_val_DMACR, reg_val_GCR;
unsigned long flags;
/* Check msp state whether in RUN or CONFIGURED Mode */
if (msp->msp_state == MSP_STATE_IDLE) {
spin_lock_irqsave(&msp_rxtx_lock, flags);
if (msp->pinctrl_rxtx_ref == 0 &&
!(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
retval = pinctrl_select_state(msp->pinctrl_p,
msp->pinctrl_def);
if (retval)
pr_err("could not set MSP defstate\n");
}
if (!retval)
msp->pinctrl_rxtx_ref++;
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
}
/* Configure msp with protocol dependent settings */ /* Configure msp with protocol dependent settings */
configure_protocol(msp, config); configure_protocol(msp, config);
...@@ -387,12 +367,14 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) ...@@ -387,12 +367,14 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
} }
/* Make sure the correct DMA-directions are configured */ /* Make sure the correct DMA-directions are configured */
if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) { if ((config->direction & MSP_DIR_RX) &&
!msp->capture_dma_data.dma_cfg) {
dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!", dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
__func__); __func__);
return -EINVAL; return -EINVAL;
} }
if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) { if ((config->direction == MSP_DIR_TX) &&
!msp->playback_dma_data.dma_cfg) {
dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!", dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
__func__); __func__);
return -EINVAL; return -EINVAL;
...@@ -630,8 +612,7 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) ...@@ -630,8 +612,7 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
{ {
int status = 0, retval = 0; int status = 0;
unsigned long flags;
dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir); dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
...@@ -643,18 +624,6 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) ...@@ -643,18 +624,6 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
(~(FRAME_GEN_ENABLE | SRG_ENABLE))), (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
msp->registers + MSP_GCR); msp->registers + MSP_GCR);
spin_lock_irqsave(&msp_rxtx_lock, flags);
WARN_ON(!msp->pinctrl_rxtx_ref);
msp->pinctrl_rxtx_ref--;
if (msp->pinctrl_rxtx_ref == 0 &&
!(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
retval = pinctrl_select_state(msp->pinctrl_p,
msp->pinctrl_sleep);
if (retval)
pr_err("could not set MSP sleepstate\n");
}
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
writel(0, msp->registers + MSP_GCR); writel(0, msp->registers + MSP_GCR);
writel(0, msp->registers + MSP_TCF); writel(0, msp->registers + MSP_TCF);
writel(0, msp->registers + MSP_RCF); writel(0, msp->registers + MSP_RCF);
...@@ -682,7 +651,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -682,7 +651,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
struct msp_i2s_platform_data *platform_data) struct msp_i2s_platform_data *platform_data)
{ {
struct resource *res = NULL; struct resource *res = NULL;
struct i2s_controller *i2s_cont;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct ux500_msp *msp; struct ux500_msp *msp;
...@@ -707,8 +675,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -707,8 +675,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
msp->id = platform_data->id; msp->id = platform_data->id;
msp->dev = &pdev->dev; msp->dev = &pdev->dev;
msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx; msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx; msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) { if (res == NULL) {
...@@ -717,6 +685,9 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -717,6 +685,9 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
return -ENOMEM; return -ENOMEM;
} }
msp->playback_dma_data.tx_rx_addr = res->start + MSP_DR;
msp->capture_dma_data.tx_rx_addr = res->start + MSP_DR;
msp->registers = devm_ioremap(&pdev->dev, res->start, msp->registers = devm_ioremap(&pdev->dev, res->start,
resource_size(res)); resource_size(res));
if (msp->registers == NULL) { if (msp->registers == NULL) {
...@@ -727,41 +698,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -727,41 +698,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
msp->msp_state = MSP_STATE_IDLE; msp->msp_state = MSP_STATE_IDLE;
msp->loopback_enable = 0; msp->loopback_enable = 0;
/* I2S-controller is allocated and added in I2S controller class. */
i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
if (!i2s_cont) {
dev_err(&pdev->dev,
"%s: ERROR: Failed to allocate I2S-controller!\n",
__func__);
return -ENOMEM;
}
i2s_cont->dev.parent = &pdev->dev;
i2s_cont->data = (void *)msp;
i2s_cont->id = (s16)msp->id;
snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
msp->id);
dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
msp->i2s_cont = i2s_cont;
msp->pinctrl_p = pinctrl_get(msp->dev);
if (IS_ERR(msp->pinctrl_p))
dev_err(&pdev->dev, "could not get MSP pinctrl\n");
else {
msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(msp->pinctrl_def)) {
dev_err(&pdev->dev,
"could not get MSP defstate (%li)\n",
PTR_ERR(msp->pinctrl_def));
}
msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
PINCTRL_STATE_SLEEP);
if (IS_ERR(msp->pinctrl_sleep))
dev_err(&pdev->dev,
"could not get MSP idlestate (%li)\n",
PTR_ERR(msp->pinctrl_def));
}
return 0; return 0;
} }
...@@ -769,8 +705,6 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev, ...@@ -769,8 +705,6 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
struct ux500_msp *msp) struct ux500_msp *msp)
{ {
dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id); dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
device_unregister(&msp->i2s_cont->dev);
} }
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define UX500_MSP_I2S_H #define UX500_MSP_I2S_H
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/asoc-ux500-msp.h>
#define MSP_INPUT_FREQ_APB 48000000 #define MSP_INPUT_FREQ_APB 48000000
...@@ -341,11 +342,6 @@ enum msp_compress_mode { ...@@ -341,11 +342,6 @@ enum msp_compress_mode {
MSP_COMPRESS_MODE_A_LAW = 3 MSP_COMPRESS_MODE_A_LAW = 3
}; };
enum msp_spi_burst_mode {
MSP_SPI_BURST_MODE_DISABLE = 0,
MSP_SPI_BURST_MODE_ENABLE = 1
};
enum msp_expand_mode { enum msp_expand_mode {
MSP_EXPAND_MODE_LINEAR = 0, MSP_EXPAND_MODE_LINEAR = 0,
MSP_EXPAND_MODE_LINEAR_SIGNED = 1, MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
...@@ -370,13 +366,6 @@ enum msp_protocol { ...@@ -370,13 +366,6 @@ enum msp_protocol {
*/ */
#define MAX_MSP_BACKUP_REGS 36 #define MAX_MSP_BACKUP_REGS 36
enum enum_i2s_controller {
MSP_0_I2S_CONTROLLER = 0,
MSP_1_I2S_CONTROLLER,
MSP_2_I2S_CONTROLLER,
MSP_3_I2S_CONTROLLER,
};
enum i2s_direction_t { enum i2s_direction_t {
MSP_DIR_TX = 0x01, MSP_DIR_TX = 0x01,
MSP_DIR_RX = 0x02, MSP_DIR_RX = 0x02,
...@@ -454,32 +443,6 @@ struct msp_protdesc { ...@@ -454,32 +443,6 @@ struct msp_protdesc {
u32 clocks_per_frame; u32 clocks_per_frame;
}; };
struct i2s_message {
enum i2s_direction_t i2s_direction;
void *txdata;
void *rxdata;
size_t txbytes;
size_t rxbytes;
int dma_flag;
int tx_offset;
int rx_offset;
bool cyclic_dma;
dma_addr_t buf_addr;
size_t buf_len;
size_t period_len;
};
struct i2s_controller {
struct module *owner;
unsigned int id;
unsigned int class;
const struct i2s_algorithm *algo; /* the algorithm to access the bus */
void *data;
struct mutex bus_lock;
struct device dev; /* the controller device */
char name[48];
};
struct ux500_msp_config { struct ux500_msp_config {
unsigned int f_inputclk; unsigned int f_inputclk;
unsigned int rx_clk_sel; unsigned int rx_clk_sel;
...@@ -491,8 +454,6 @@ struct ux500_msp_config { ...@@ -491,8 +454,6 @@ struct ux500_msp_config {
unsigned int tx_fsync_sel; unsigned int tx_fsync_sel;
unsigned int rx_fifo_config; unsigned int rx_fifo_config;
unsigned int tx_fifo_config; unsigned int tx_fifo_config;
unsigned int spi_clk_mode;
unsigned int spi_burst_mode;
unsigned int loopback_enable; unsigned int loopback_enable;
unsigned int tx_data_enable; unsigned int tx_data_enable;
unsigned int default_protdesc; unsigned int default_protdesc;
...@@ -502,43 +463,28 @@ struct ux500_msp_config { ...@@ -502,43 +463,28 @@ struct ux500_msp_config {
unsigned int direction; unsigned int direction;
unsigned int protocol; unsigned int protocol;
unsigned int frame_freq; unsigned int frame_freq;
unsigned int frame_size;
enum msp_data_size data_size; enum msp_data_size data_size;
unsigned int def_elem_len; unsigned int def_elem_len;
unsigned int iodelay; unsigned int iodelay;
void (*handler) (void *data); };
void *tx_callback_data;
void *rx_callback_data; struct ux500_msp_dma_params {
unsigned int data_size;
dma_addr_t tx_rx_addr;
struct stedma40_chan_cfg *dma_cfg;
}; };
struct ux500_msp { struct ux500_msp {
enum enum_i2s_controller id; enum msp_i2s_id id;
void __iomem *registers; void __iomem *registers;
struct device *dev; struct device *dev;
struct i2s_controller *i2s_cont; struct ux500_msp_dma_params playback_dma_data;
struct stedma40_chan_cfg *dma_cfg_rx; struct ux500_msp_dma_params capture_dma_data;
struct stedma40_chan_cfg *dma_cfg_tx;
struct dma_chan *tx_pipeid;
struct dma_chan *rx_pipeid;
enum msp_state msp_state; enum msp_state msp_state;
int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
struct timer_list notify_timer;
int def_elem_len; int def_elem_len;
unsigned int dir_busy; unsigned int dir_busy;
int loopback_enable; int loopback_enable;
u32 backup_regs[MAX_MSP_BACKUP_REGS];
unsigned int f_bitclk; unsigned int f_bitclk;
/* Pin modes */
struct pinctrl *pinctrl_p;
struct pinctrl_state *pinctrl_def;
struct pinctrl_state *pinctrl_sleep;
/* Reference Count */
int pinctrl_rxtx_ref;
};
struct ux500_msp_dma_params {
unsigned int data_size;
struct stedma40_chan_cfg *dma_cfg;
}; };
struct msp_i2s_platform_data; struct msp_i2s_platform_data;
......
...@@ -103,10 +103,40 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, ...@@ -103,10 +103,40 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
} }
static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct dma_slave_config *slave_config)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct ux500_msp_dma_params *dma_params;
struct stedma40_chan_cfg *dma_cfg;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dma_cfg = dma_params->dma_cfg;
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
if (ret)
return ret;
slave_config->dst_maxburst = 4;
slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
slave_config->src_maxburst = 4;
slave_config->src_addr_width = dma_cfg->src_info.data_width;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
slave_config->dst_addr = dma_params->tx_rx_addr;
else
slave_config->src_addr = dma_params->tx_rx_addr;
return 0;
}
static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
.pcm_hardware = &ux500_pcm_hw, .pcm_hardware = &ux500_pcm_hw,
.compat_request_channel = ux500_pcm_request_chan, .compat_request_channel = ux500_pcm_request_chan,
.prealloc_buffer_size = 128 * 1024, .prealloc_buffer_size = 128 * 1024,
.prepare_slave_config = ux500_pcm_prepare_slave_config,
}; };
int ux500_pcm_register_platform(struct platform_device *pdev) int ux500_pcm_register_platform(struct platform_device *pdev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment