aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/ti/davinci-mcasp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/ti/davinci-mcasp.c')
-rw-r--r--sound/soc/ti/davinci-mcasp.c311
1 files changed, 220 insertions, 91 deletions
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index eeda6d5565bc..a3a67a8f0f54 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -29,6 +29,7 @@
#include <linux/platform_data/davinci_asp.h>
#include <linux/math64.h>
#include <linux/bitmap.h>
+#include <linux/gpio/driver.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -54,6 +55,7 @@ static u32 context_regs[] = {
DAVINCI_MCASP_AHCLKXCTL_REG,
DAVINCI_MCASP_AHCLKRCTL_REG,
DAVINCI_MCASP_PDIR_REG,
+ DAVINCI_MCASP_PFUNC_REG,
DAVINCI_MCASP_RXMASK_REG,
DAVINCI_MCASP_TXMASK_REG,
DAVINCI_MCASP_RXTDM_REG,
@@ -108,7 +110,11 @@ struct davinci_mcasp {
/* Used for comstraint setting on the second stream */
u32 channels;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
+
+#ifdef CONFIG_PM
struct davinci_mcasp_context context;
#endif
@@ -818,9 +824,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
- /* All PINS as McASP */
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
-
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
@@ -1486,74 +1489,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
-{
- struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
- struct davinci_mcasp_context *context = &mcasp->context;
- u32 reg;
- int i;
-
- context->pm_state = pm_runtime_active(mcasp->dev);
- if (!context->pm_state)
- pm_runtime_get_sync(mcasp->dev);
-
- for (i = 0; i < ARRAY_SIZE(context_regs); i++)
- context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
-
- if (mcasp->txnumevt) {
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
- }
- if (mcasp->rxnumevt) {
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
- }
-
- for (i = 0; i < mcasp->num_serializer; i++)
- context->xrsr_regs[i] = mcasp_get_reg(mcasp,
- DAVINCI_MCASP_XRSRCTL_REG(i));
-
- pm_runtime_put_sync(mcasp->dev);
-
- return 0;
-}
-
-static int davinci_mcasp_resume(struct snd_soc_dai *dai)
-{
- struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
- struct davinci_mcasp_context *context = &mcasp->context;
- u32 reg;
- int i;
-
- pm_runtime_get_sync(mcasp->dev);
-
- for (i = 0; i < ARRAY_SIZE(context_regs); i++)
- mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
-
- if (mcasp->txnumevt) {
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
- }
- if (mcasp->rxnumevt) {
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
- }
-
- for (i = 0; i < mcasp->num_serializer; i++)
- mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
- context->xrsr_regs[i]);
-
- if (!context->pm_state)
- pm_runtime_put_sync(mcasp->dev);
-
- return 0;
-}
-#else
-#define davinci_mcasp_suspend NULL
-#define davinci_mcasp_resume NULL
-#endif
-
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -1571,8 +1506,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
.probe = davinci_mcasp_dai_probe,
- .suspend = davinci_mcasp_suspend,
- .resume = davinci_mcasp_resume,
.playback = {
.channels_min = 1,
.channels_max = 32 * 16,
@@ -1915,6 +1848,147 @@ static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
return offset;
}
+#ifdef CONFIG_GPIOLIB
+static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+
+ if (mcasp->num_serializer && offset < mcasp->num_serializer &&
+ mcasp->serial_dir[offset] != INACTIVE_MODE) {
+ dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset);
+ return -EBUSY;
+ }
+
+ /* Do not change the PIN yet */
+
+ return pm_runtime_get_sync(mcasp->dev);
+}
+
+static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+
+ /* Set the direction to input */
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
+
+ /* Set the pin as McASP pin */
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
+
+ pm_runtime_put_sync(mcasp->dev);
+}
+
+static int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+ u32 val;
+
+ if (value)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
+
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
+ if (!(val & BIT(offset))) {
+ /* Set the pin as GPIO pin */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
+
+ /* Set the direction to output */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
+ }
+
+ return 0;
+}
+
+static void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+
+ if (value)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
+}
+
+static int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+ u32 val;
+
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
+ if (!(val & BIT(offset))) {
+ /* Set the direction to input */
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
+
+ /* Set the pin as GPIO pin */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
+ }
+
+ return 0;
+}
+
+static int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+ u32 val;
+
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG);
+ if (val & BIT(offset))
+ return 1;
+
+ return 0;
+}
+
+static int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
+ u32 val;
+
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+ if (val & BIT(offset))
+ return 0;
+
+ return 1;
+}
+
+static const struct gpio_chip davinci_mcasp_template_chip = {
+ .owner = THIS_MODULE,
+ .request = davinci_mcasp_gpio_request,
+ .free = davinci_mcasp_gpio_free,
+ .direction_output = davinci_mcasp_gpio_direction_out,
+ .set = davinci_mcasp_gpio_set,
+ .direction_input = davinci_mcasp_gpio_direction_in,
+ .get = davinci_mcasp_gpio_get,
+ .get_direction = davinci_mcasp_gpio_get_direction,
+ .base = -1,
+ .ngpio = 32,
+};
+
+static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
+{
+ if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
+ return 0;
+
+ mcasp->gpio_chip = davinci_mcasp_template_chip;
+ mcasp->gpio_chip.label = dev_name(mcasp->dev);
+ mcasp->gpio_chip.parent = mcasp->dev;
+#ifdef CONFIG_OF_GPIO
+ mcasp->gpio_chip.of_node = mcasp->dev->of_node;
+#endif
+
+ return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp);
+}
+
+#else /* CONFIG_GPIOLIB */
+static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
+{
+ return 0;
+}
+#endif /* CONFIG_GPIOLIB */
+
static int davinci_mcasp_probe(struct platform_device *pdev)
{
struct snd_dmaengine_dai_dma_data *dma_data;
@@ -1976,7 +2050,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
}
mcasp->num_serializer = pdata->num_serializer;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
mcasp->num_serializer, sizeof(u32),
GFP_KERNEL);
@@ -2139,6 +2213,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp_reparent_fck(pdev);
+ /* All PINS as McASP */
+ pm_runtime_get_sync(mcasp->dev);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+ pm_runtime_put(mcasp->dev);
+
+ ret = davinci_mcasp_init_gpiochip(mcasp);
+ if (ret)
+ goto err;
+
ret = devm_snd_soc_register_component(&pdev->dev,
&davinci_mcasp_component,
&davinci_mcasp_dai[pdata->op_mode], 1);
@@ -2149,26 +2232,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = davinci_mcasp_get_dma_type(mcasp);
switch (ret) {
case PCM_EDMA:
-#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \
- (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
- IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM))
ret = edma_pcm_platform_register(&pdev->dev);
-#else
- dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
- ret = -EINVAL;
- goto err;
-#endif
break;
case PCM_SDMA:
-#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \
- (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
- IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM))
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
-#else
- dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
- ret = -EINVAL;
- goto err;
-#endif
break;
default:
dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
@@ -2196,11 +2263,73 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int davinci_mcasp_runtime_suspend(struct device *dev)
+{
+ struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
+ struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+ }
+
+ for (i = 0; i < mcasp->num_serializer; i++)
+ context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+ DAVINCI_MCASP_XRSRCTL_REG(i));
+
+ return 0;
+}
+
+static int davinci_mcasp_runtime_resume(struct device *dev)
+{
+ struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
+ struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+ }
+
+ for (i = 0; i < mcasp->num_serializer; i++)
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ context->xrsr_regs[i]);
+
+ return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops davinci_mcasp_pm_ops = {
+ SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
+ davinci_mcasp_runtime_resume,
+ NULL)
+};
+
static struct platform_driver davinci_mcasp_driver = {
.probe = davinci_mcasp_probe,
.remove = davinci_mcasp_remove,
.driver = {
.name = "davinci-mcasp",
+ .pm = &davinci_mcasp_pm_ops,
.of_match_table = mcasp_dt_ids,
},
};