mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 17:11:33 +00:00
Merge remote-tracking branch 'asoc/topic/ux500' into asoc-next
This commit is contained in:
commit
458bcee95d
@ -2236,7 +2236,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
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) |
|
||||
BIT(AB8500_DIGIFCONF2_IF0WL1);
|
||||
@ -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);
|
||||
|
||||
/* Setup TDM DA according to active tx slots */
|
||||
|
||||
if (tx_mask & ~0xff)
|
||||
return -EINVAL;
|
||||
|
||||
mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
|
||||
tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
|
||||
slots_active = hweight32(tx_mask);
|
||||
|
||||
dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
|
||||
slots_active);
|
||||
|
||||
switch (slots_active) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* Slot 9 -> DA_IN1 & DA_IN3 */
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
|
||||
slot = find_first_bit((unsigned long *)&tx_mask, 32);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
|
||||
break;
|
||||
case 2:
|
||||
/* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
|
||||
|
||||
slot = find_first_bit((unsigned long *)&tx_mask, 32);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
|
||||
slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
|
||||
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
|
||||
break;
|
||||
case 8:
|
||||
dev_dbg(dai->codec->dev,
|
||||
@ -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 */
|
||||
|
||||
if (rx_mask & ~0xff)
|
||||
return -EINVAL;
|
||||
|
||||
rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
|
||||
slots_active = hweight32(rx_mask);
|
||||
|
||||
dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
|
||||
slots_active);
|
||||
|
||||
switch (slots_active) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* AD_OUT3 -> slot 0 & 1 */
|
||||
snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL,
|
||||
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
|
||||
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD);
|
||||
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));
|
||||
break;
|
||||
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_ADSLOTSEL1,
|
||||
AB8500_MASK_ALL,
|
||||
AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
|
||||
AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
|
||||
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,
|
||||
AB8500_ADSLOTSEL(slot),
|
||||
AB8500_MASK_SLOT(slot),
|
||||
AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
|
||||
break;
|
||||
case 8:
|
||||
dev_dbg(dai->codec->dev,
|
||||
@ -2362,6 +2380,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
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[] = {
|
||||
{
|
||||
.name = "ab8500-codec-dai.0",
|
||||
@ -2373,12 +2396,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
|
||||
.rates = AB8500_SUPPORTED_RATE,
|
||||
.formats = AB8500_SUPPORTED_FMT,
|
||||
},
|
||||
.ops = (struct snd_soc_dai_ops[]) {
|
||||
{
|
||||
.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
|
||||
.set_fmt = ab8500_codec_set_dai_fmt,
|
||||
}
|
||||
},
|
||||
.ops = &ab8500_codec_ops,
|
||||
.symmetric_rates = 1
|
||||
},
|
||||
{
|
||||
@ -2391,12 +2409,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
|
||||
.rates = AB8500_SUPPORTED_RATE,
|
||||
.formats = AB8500_SUPPORTED_FMT,
|
||||
},
|
||||
.ops = (struct snd_soc_dai_ops[]) {
|
||||
{
|
||||
.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
|
||||
.set_fmt = ab8500_codec_set_dai_fmt,
|
||||
}
|
||||
},
|
||||
.ops = &ab8500_codec_ops,
|
||||
.symmetric_rates = 1
|
||||
}
|
||||
};
|
||||
|
@ -24,6 +24,13 @@
|
||||
#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
|
||||
#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 */
|
||||
|
||||
#define AB8500_POWERUP 0x00
|
||||
@ -73,6 +80,7 @@
|
||||
#define AB8500_ADSLOTSEL14 0x2C
|
||||
#define AB8500_ADSLOTSEL15 0x2D
|
||||
#define AB8500_ADSLOTSEL16 0x2E
|
||||
#define AB8500_ADSLOTSEL(slot) (AB8500_ADSLOTSEL1 + (slot >> 1))
|
||||
#define AB8500_ADSLOTHIZCTRL1 0x2F
|
||||
#define AB8500_ADSLOTHIZCTRL2 0x30
|
||||
#define AB8500_ADSLOTHIZCTRL3 0x31
|
||||
@ -144,6 +152,7 @@
|
||||
#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1)
|
||||
|
||||
#define AB8500_MASK_ALL 0xFF
|
||||
#define AB8500_MASK_SLOT(slot) ((slot & 1) ? 0xF0 : 0x0F)
|
||||
#define AB8500_MASK_NONE 0x00
|
||||
|
||||
/* AB8500_POWERUP */
|
||||
@ -347,28 +356,21 @@
|
||||
#define AB8500_DIGIFCONF4_IF1WL0 0
|
||||
|
||||
/* AB8500_ADSLOTSELX */
|
||||
#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00
|
||||
#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x10
|
||||
#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x20
|
||||
#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x30
|
||||
#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x40
|
||||
#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x50
|
||||
#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x60
|
||||
#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x70
|
||||
#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x80
|
||||
#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0xF0
|
||||
#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_AD_OUT1 0x0
|
||||
#define AB8500_AD_OUT2 0x1
|
||||
#define AB8500_AD_OUT3 0x2
|
||||
#define AB8500_AD_OUT4 0x3
|
||||
#define AB8500_AD_OUT5 0x4
|
||||
#define AB8500_AD_OUT6 0x5
|
||||
#define AB8500_AD_OUT7 0x6
|
||||
#define AB8500_AD_OUT8 0x7
|
||||
#define AB8500_ZEROES 0x8
|
||||
#define AB8500_TRISTATE 0xF
|
||||
#define AB8500_ADSLOTSELX_EVEN_SHIFT 0
|
||||
#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_ADSLOTHIZCTRL2 */
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
@ -24,6 +25,7 @@
|
||||
|
||||
#include "ux500_pcm.h"
|
||||
#include "ux500_msp_dai.h"
|
||||
#include "mop500_ab8500.h"
|
||||
#include "../codecs/ab8500-codec.h"
|
||||
|
||||
#define TX_SLOT_MONO 0x0008
|
||||
@ -43,6 +45,12 @@
|
||||
static unsigned int tx_slots = DEF_TX_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 */
|
||||
static const char * const enum_mclk[] = {
|
||||
"SYSCLK",
|
||||
@ -230,6 +238,21 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
|
||||
substream->name,
|
||||
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);
|
||||
|
||||
switch (params_format(params)) {
|
||||
@ -328,9 +351,22 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
|
||||
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[] = {
|
||||
{
|
||||
.hw_params = mop500_ab8500_hw_params,
|
||||
.hw_free = mop500_ab8500_hw_free,
|
||||
.startup = mop500_ab8500_startup,
|
||||
.shutdown = mop500_ab8500_shutdown,
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
|
||||
drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
|
||||
dai->playback_dma_data = &drvdata->msp->playback_dma_data;
|
||||
dai->capture_dma_data = &drvdata->msp->capture_dma_data;
|
||||
|
||||
dai->playback_dma_data = &drvdata->playback_dma_data;
|
||||
dai->capture_dma_data = &drvdata->capture_dma_data;
|
||||
|
||||
drvdata->playback_dma_data.data_size = drvdata->slot_width;
|
||||
drvdata->capture_dma_data.data_size = drvdata->slot_width;
|
||||
drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
|
||||
drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,15 +51,11 @@ enum ux500_msp_clock_id {
|
||||
struct ux500_msp_i2s_drvdata {
|
||||
struct ux500_msp *msp;
|
||||
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 tx_mask;
|
||||
unsigned int rx_mask;
|
||||
int slots;
|
||||
int slot_width;
|
||||
u8 configured;
|
||||
int data_delay;
|
||||
|
||||
/* Clocks */
|
||||
unsigned int master_clk;
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
@ -26,9 +25,6 @@
|
||||
|
||||
#include "ux500_msp_i2s.h"
|
||||
|
||||
/* MSP1/3 Tx/Rx usage protection */
|
||||
static DEFINE_SPINLOCK(msp_rxtx_lock);
|
||||
|
||||
/* Protocol desciptors */
|
||||
static const struct msp_protdesc prot_descs[] = {
|
||||
{ /* I2S */
|
||||
@ -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)
|
||||
{
|
||||
int status = 0, retval = 0;
|
||||
int status = 0;
|
||||
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_protocol(msp, 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 */
|
||||
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!",
|
||||
__func__);
|
||||
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!",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
@ -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 status = 0, retval = 0;
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
|
||||
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)
|
||||
(~(FRAME_GEN_ENABLE | SRG_ENABLE))),
|
||||
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_TCF);
|
||||
writel(0, msp->registers + MSP_RCF);
|
||||
@ -682,7 +651,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
|
||||
struct msp_i2s_platform_data *platform_data)
|
||||
{
|
||||
struct resource *res = NULL;
|
||||
struct i2s_controller *i2s_cont;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ux500_msp *msp;
|
||||
|
||||
@ -707,8 +675,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
|
||||
|
||||
msp->id = platform_data->id;
|
||||
msp->dev = &pdev->dev;
|
||||
msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
|
||||
msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
|
||||
msp->playback_dma_data.dma_cfg = 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);
|
||||
if (res == NULL) {
|
||||
@ -717,6 +685,9 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
|
||||
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,
|
||||
resource_size(res));
|
||||
if (msp->registers == NULL) {
|
||||
@ -727,41 +698,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
|
||||
msp->msp_state = MSP_STATE_IDLE;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -769,8 +705,6 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
|
||||
struct ux500_msp *msp)
|
||||
{
|
||||
dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
|
||||
|
||||
device_unregister(&msp->i2s_cont->dev);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define UX500_MSP_I2S_H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/asoc-ux500-msp.h>
|
||||
|
||||
#define MSP_INPUT_FREQ_APB 48000000
|
||||
|
||||
@ -341,11 +342,6 @@ enum msp_compress_mode {
|
||||
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 {
|
||||
MSP_EXPAND_MODE_LINEAR = 0,
|
||||
MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
|
||||
@ -370,13 +366,6 @@ enum msp_protocol {
|
||||
*/
|
||||
#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 {
|
||||
MSP_DIR_TX = 0x01,
|
||||
MSP_DIR_RX = 0x02,
|
||||
@ -454,32 +443,6 @@ struct msp_protdesc {
|
||||
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 {
|
||||
unsigned int f_inputclk;
|
||||
unsigned int rx_clk_sel;
|
||||
@ -491,8 +454,6 @@ struct ux500_msp_config {
|
||||
unsigned int tx_fsync_sel;
|
||||
unsigned int rx_fifo_config;
|
||||
unsigned int tx_fifo_config;
|
||||
unsigned int spi_clk_mode;
|
||||
unsigned int spi_burst_mode;
|
||||
unsigned int loopback_enable;
|
||||
unsigned int tx_data_enable;
|
||||
unsigned int default_protdesc;
|
||||
@ -502,45 +463,30 @@ struct ux500_msp_config {
|
||||
unsigned int direction;
|
||||
unsigned int protocol;
|
||||
unsigned int frame_freq;
|
||||
unsigned int frame_size;
|
||||
enum msp_data_size data_size;
|
||||
unsigned int def_elem_len;
|
||||
unsigned int iodelay;
|
||||
void (*handler) (void *data);
|
||||
void *tx_callback_data;
|
||||
void *rx_callback_data;
|
||||
};
|
||||
|
||||
struct ux500_msp {
|
||||
enum enum_i2s_controller id;
|
||||
void __iomem *registers;
|
||||
struct device *dev;
|
||||
struct i2s_controller *i2s_cont;
|
||||
struct stedma40_chan_cfg *dma_cfg_rx;
|
||||
struct stedma40_chan_cfg *dma_cfg_tx;
|
||||
struct dma_chan *tx_pipeid;
|
||||
struct dma_chan *rx_pipeid;
|
||||
enum msp_state msp_state;
|
||||
int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
|
||||
struct timer_list notify_timer;
|
||||
int def_elem_len;
|
||||
unsigned int dir_busy;
|
||||
int loopback_enable;
|
||||
u32 backup_regs[MAX_MSP_BACKUP_REGS];
|
||||
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;
|
||||
dma_addr_t tx_rx_addr;
|
||||
struct stedma40_chan_cfg *dma_cfg;
|
||||
};
|
||||
|
||||
struct ux500_msp {
|
||||
enum msp_i2s_id id;
|
||||
void __iomem *registers;
|
||||
struct device *dev;
|
||||
struct ux500_msp_dma_params playback_dma_data;
|
||||
struct ux500_msp_dma_params capture_dma_data;
|
||||
enum msp_state msp_state;
|
||||
int def_elem_len;
|
||||
unsigned int dir_busy;
|
||||
int loopback_enable;
|
||||
unsigned int f_bitclk;
|
||||
};
|
||||
|
||||
struct msp_i2s_platform_data;
|
||||
int ux500_msp_i2s_init_msp(struct platform_device *pdev,
|
||||
struct ux500_msp **msp_p,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.pcm_hardware = &ux500_pcm_hw,
|
||||
.compat_request_channel = ux500_pcm_request_chan,
|
||||
.prealloc_buffer_size = 128 * 1024,
|
||||
.prepare_slave_config = ux500_pcm_prepare_slave_config,
|
||||
};
|
||||
|
||||
int ux500_pcm_register_platform(struct platform_device *pdev)
|
||||
|
Loading…
Reference in New Issue
Block a user