提交 458bcee9 编写于 作者: M Mark Brown

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

......@@ -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_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_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_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,43 +463,28 @@ 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_dma_params {
unsigned int data_size;
dma_addr_t tx_rx_addr;
struct stedma40_chan_cfg *dma_cfg;
};
struct ux500_msp {
enum enum_i2s_controller id;
enum msp_i2s_id 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;
struct ux500_msp_dma_params playback_dma_data;
struct ux500_msp_dma_params capture_dma_data;
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;
struct stedma40_chan_cfg *dma_cfg;
};
struct msp_i2s_platform_data;
......
......@@ -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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册