From b296263398f08d21e68d5d7b2afc43228c208b71 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 21 May 2013 12:04:08 +0200 Subject: ASoC: ab8500-codec: Set tx dai slots from tx_mask Replace hard-coded tx slot numbers from ab8500_codec_set_dai_tdm_slot using the ones requested by the machine driver in tx_mask instead. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 3126cac..bace321 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -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, diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h index 114f69a..4224b52 100644 --- a/sound/soc/codecs/ab8500-codec.h +++ b/sound/soc/codecs/ab8500-codec.h @@ -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 -- cgit v0.10.2 From da33d723bcb3569400685b4e6e75a9894e2f42a7 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 21 May 2013 12:04:09 +0200 Subject: ASoC: ab8500-codec: Set rx dai slots from rx_mask Replace hard coded rx slot numbers from ab8500_codec_set_dai_tdm_slot using the ones requested by the machine driver in rx_mask instead. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index bace321..4ca45b9 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2334,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, diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h index 64c14ce..e2e5442 100644 --- a/sound/soc/codecs/ab8500-codec.h +++ b/sound/soc/codecs/ab8500-codec.h @@ -80,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 @@ -151,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 */ @@ -354,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 */ -- cgit v0.10.2 From 6ee0b4b0ef871632b067f216b3032bf8db93c510 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:15 +0200 Subject: ASoC: ux500: Drop pinctrl sleep support Drop pinctrl default/sleep state switching code, as it was breaking the capture interface by putting the I2S pins in hi-z mode regardless of its usage status, and not giving any real benefit. Pinctrl default mode configuration is already managed automatically by a specific pinctrl hog. Signed-off-by: Fabio Baltieri Acked-by: Linus Walleij Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index f2db6c9..b029b2d 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -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); @@ -630,8 +610,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 +622,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); @@ -743,25 +710,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, 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; } diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index e5cd105..8ce014e 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -528,12 +528,6 @@ struct ux500_msp { 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 { -- cgit v0.10.2 From 7f92581b21707bfe09e14410283692b658b9ef10 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:16 +0200 Subject: ASoC: ab8500-codec: Move codec ops on a separate structure Define ab8500 codec operations structure on its own rather than inline with snd_soc_dai_drivers to clean up the code and make the style coherent with other codec drivers. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 4ca45b9..b8ba0ad 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2380,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", @@ -2391,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 }, { @@ -2409,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 } }; -- cgit v0.10.2 From b7230d7e4c1f6a87ddb96dbc106435e0dfee0f37 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:17 +0200 Subject: ASoC: ux500: Drop dangling struct i2s_controller Drop struct i2s_controller from the ux500 ASoC driver as right now it is instantiated but not used anywhere. Also drop a mismatched device_unregister in the process. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index b029b2d..cba0e86 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -649,7 +649,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; @@ -694,22 +693,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; - return 0; } @@ -717,8 +700,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"); diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 8ce014e..ccfcc32 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -469,17 +469,6 @@ struct i2s_message { 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; @@ -515,7 +504,6 @@ 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; -- cgit v0.10.2 From 2a357137fac4e2e92d13d37b161a6ff4535eecc6 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:18 +0200 Subject: ASoC: ux500: Drop unused code from msp headers Drop unused fields and structures from ux500_msp_i2s header file, as those looks like leftover from a previous implementation of the driver. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index f531043..c721282 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -58,8 +58,6 @@ struct ux500_msp_i2s_drvdata { unsigned int rx_mask; int slots; int slot_width; - u8 configured; - int data_delay; /* Clocks */ unsigned int master_clk; diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index ccfcc32..d5e4176 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -341,11 +341,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, @@ -454,21 +449,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 ux500_msp_config { unsigned int f_inputclk; unsigned int rx_clk_sel; @@ -480,8 +460,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; @@ -491,13 +469,9 @@ 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 { @@ -506,15 +480,10 @@ struct ux500_msp { struct device *dev; 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; }; -- cgit v0.10.2 From 06b9671ee69d48a1436077805903e3d9c1ed9662 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:19 +0200 Subject: ASoC: ux500: Add missing mop500_ab8500.h include Add a missing include that was resulting in some sparse warning for non-static structure without forward declaration. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 884a362..5e0f146 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -24,6 +24,7 @@ #include "ux500_pcm.h" #include "ux500_msp_dai.h" +#include "mop500_ab8500.h" #include "../codecs/ab8500-codec.h" #define TX_SLOT_MONO 0x0008 -- cgit v0.10.2 From f82030f978ae21ee790a90610ff21ce72667958e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 24 May 2013 12:39:20 +0200 Subject: ASoC: ux500: Drop redundant msp id enumerations Ux500 has two equivalent enum for device id, one in platform_data and one in a local header. Fix this by dropping the local one. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index d5e4176..189a375 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -16,6 +16,7 @@ #define UX500_MSP_I2S_H #include +#include #define MSP_INPUT_FREQ_APB 48000000 @@ -365,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, @@ -475,7 +469,7 @@ struct ux500_msp_config { }; struct ux500_msp { - enum enum_i2s_controller id; + enum msp_i2s_id id; void __iomem *registers; struct device *dev; struct stedma40_chan_cfg *dma_cfg_rx; -- cgit v0.10.2 From a130243b96622e16af7c1ac7ba903b4cec7aa81b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 28 May 2013 16:16:39 +0200 Subject: ASoC: ux500: Ensure consistent configuration between DAIs Current implementation of mop500_ab8500 allows for inconsistent sample rate and channel count configuration between the playback and recording interfaces, through in the hardware the two MSP controllers share common clock and frame sync signals. This patch adds the necessary code to ensure that the two device are configure consistently. The check is added at machine driver level, as how to lock DAI configuration depend of the actual hardware implementation. Signed-off-by: Fabio Baltieri Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 5e0f146..7e923ec 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -44,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", @@ -231,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)) { @@ -329,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, } -- cgit v0.10.2 From f3fe53dd975306903be3616c87865a87a52fb20e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 12 Jun 2013 09:57:57 +0200 Subject: ASoC: ux500: Move DMA parameters into ux500_msp Move struct ux500_msp_dma_params declaration from ux500_msp_i2s_drvdata to ux500_msp, this saves some confusing pointer passing and allows to access all DMA configuration fields from ux500_msp_i2s. Signed-off-by: Fabio Baltieri Acked-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 7d5fc13..c6fb5cc 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -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; } diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index c721282..312ae53 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -51,8 +51,6 @@ 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; diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index cba0e86..14a4a5b 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -367,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; @@ -673,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) { diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 189a375..8796171 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -468,12 +468,17 @@ struct ux500_msp_config { unsigned int iodelay; }; +struct ux500_msp_dma_params { + unsigned int data_size; + struct stedma40_chan_cfg *dma_cfg; +}; + struct ux500_msp { enum msp_i2s_id id; void __iomem *registers; struct device *dev; - struct stedma40_chan_cfg *dma_cfg_rx; - struct stedma40_chan_cfg *dma_cfg_tx; + 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; @@ -481,11 +486,6 @@ struct ux500_msp { unsigned int f_bitclk; }; -struct ux500_msp_dma_params { - unsigned int data_size; - struct stedma40_chan_cfg *dma_cfg; -}; - struct msp_i2s_platform_data; int ux500_msp_i2s_init_msp(struct platform_device *pdev, struct ux500_msp **msp_p, -- cgit v0.10.2 From 20413113ffdd8c56b2a985ca8195d9c91e9c602b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 12 Jun 2013 09:57:58 +0200 Subject: ASoC: ux500: Set DMA address during device init Add a field with the tx/rx register address to the DMA parameters structure, and set it to the correct address during device initialization. This address used to be hardcoded in the DMA controller driver, it now needs to be explicitly figured out by the device driver. Signed-off-by: Fabio Baltieri Acked-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index 14a4a5b..1ca8b08 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -685,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) { diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 8796171..258d0bc 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -470,6 +470,7 @@ struct ux500_msp_config { struct ux500_msp_dma_params { unsigned int data_size; + dma_addr_t tx_rx_addr; struct stedma40_chan_cfg *dma_cfg; }; -- cgit v0.10.2 From eef6473ff3ce2383febebd2e799beceaece9adda Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 12 Jun 2013 09:57:59 +0200 Subject: ASoC: ux500: Add DMA slave config prepare routine Implement a DMA slave config prepare routine, as until now the MSP driver depended on the DMA controller completing the channel configuration on its own, but this is not the case anymore since the recent DMA driver updates. Signed-off-by: Fabio Baltieri Acked-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index b6e5ae2..5f01c19 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -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) -- cgit v0.10.2