Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: mmp-sspa: Add Device Tree support

This makes it possible to select CONFIG_SND_MMP_SOC_SSPA directly, as
opposed to via CONFIG_SND_MMP_SOC, and for the driver to bind to a device
tree node. That makes the driver useful on Device Tree based systems,
with audio-graph-card or simple-card.

The aforementioned card drivers control the master clock themselves and
don't call the set_dai_sysclk() or set_dai_pll(), thus the respective
handlers don't serve any purpose anymore. Instead, they return early and
the hw_params() handler sets the appropriate bitclk itself.

The register range is split into two -- for the RX block and for the TX
block. On a MMP2 there are two pairs of them; the first one has the
clock controller in the middle, while the second just has a hole:

0xd42a0c00 - 0xd42a0c30 RX1
0xd42a0c30 - 0xd42a0c40 Clocks
0xd42a0c80 - 0xd42a0cb0 TX1
0xd42a0d00 - 0xd42a0d30 RX2
0xd42a0d80 - 0xd42a0cb0 TX2

For this reason, mmp_sspa_write_reg() and mmp_sspa_read_reg() are
replaced with direct calls to I/O routines.

Tested on a MMP2-based OLPC XO-1.75 laptop with rt5631 coded, mmp_tdma DMA
engine and MMP2 clock controller glued together with audio-graph-card.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Link: https://lore.kernel.org/r/20200511210134.1224532-12-lkundrak@v3.sk
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Lubomir Rintel and committed by
Mark Brown
a97e384b ce595586

+113 -74
+10 -10
sound/soc/pxa/Kconfig
··· 9 9 to select the audio interfaces to support below. 10 10 11 11 config SND_MMP_SOC 12 - bool "Soc Audio for Marvell MMP chips" 13 - depends on ARCH_MMP 12 + bool 14 13 select MMP_SRAM 15 - select SND_SOC_GENERIC_DMAENGINE_PCM 16 - select SND_ARM 17 - help 18 - Say Y if you want to add support for codecs attached to 19 - the MMP SSPA interface. 20 14 21 15 config SND_PXA2XX_AC97 22 16 tristate ··· 33 39 select SND_PXA2XX_LIB 34 40 35 41 config SND_MMP_SOC_SSPA 36 - tristate 42 + tristate "SoC Audio via MMP SSPA ports" 43 + depends on ARCH_MMP 44 + select SND_SOC_GENERIC_DMAENGINE_PCM 45 + select SND_ARM 46 + help 47 + Say Y if you want to add support for codecs attached to 48 + the MMP SSPA interface. 37 49 38 50 config SND_PXA2XX_SOC_CORGI 39 51 tristate "SoC Audio support for Sharp Zaurus SL-C7x0" ··· 232 232 233 233 config SND_MMP_SOC_BROWNSTONE 234 234 tristate "SoC Audio support for Marvell Brownstone" 235 - depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C 236 - select SND_MMP_SOC_SSPA 235 + depends on SND_MMP_SOC_SSPA && MACH_BROWNSTONE && I2C 236 + select SND_MMP_SOC 237 237 select MFD_WM8994 238 238 select SND_SOC_WM8994 239 239 help
+94 -45
sound/soc/pxa/mmp-sspa.c
··· 28 28 * SSPA audio private data 29 29 */ 30 30 struct sspa_priv { 31 - void __iomem *mmio_base; 31 + void __iomem *tx_base; 32 + void __iomem *rx_base; 33 + 32 34 struct snd_dmaengine_dai_dma_data playback_dma_data; 33 35 struct snd_dmaengine_dai_dma_data capture_dma_data; 34 36 struct clk *clk; 35 37 struct clk *audio_clk; 36 38 struct clk *sysclk; 39 + 37 40 int running_cnt; 38 41 u32 sp; 39 42 u32 ctrl; 40 43 }; 41 - 42 - static void mmp_sspa_write_reg(struct sspa_priv *sspa, u32 reg, u32 val) 43 - { 44 - __raw_writel(val, sspa->mmio_base + reg); 45 - } 46 - 47 - static u32 mmp_sspa_read_reg(struct sspa_priv *sspa, u32 reg) 48 - { 49 - return __raw_readl(sspa->mmio_base + reg); 50 - } 51 44 52 45 static void mmp_sspa_tx_enable(struct sspa_priv *sspa) 53 46 { ··· 49 56 sspa_sp &= ~SSPA_SP_MSL; 50 57 sspa_sp |= SSPA_SP_S_EN; 51 58 sspa_sp |= SSPA_SP_WEN; 52 - mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 59 + __raw_writel(sspa_sp, sspa->tx_base + SSPA_SP); 53 60 } 54 61 55 62 static void mmp_sspa_tx_disable(struct sspa_priv *sspa) ··· 59 66 sspa_sp &= ~SSPA_SP_MSL; 60 67 sspa_sp &= ~SSPA_SP_S_EN; 61 68 sspa_sp |= SSPA_SP_WEN; 62 - mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 69 + __raw_writel(sspa_sp, sspa->tx_base + SSPA_SP); 63 70 } 64 71 65 72 static void mmp_sspa_rx_enable(struct sspa_priv *sspa) ··· 68 75 69 76 sspa_sp |= SSPA_SP_S_EN; 70 77 sspa_sp |= SSPA_SP_WEN; 71 - mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 78 + __raw_writel(sspa_sp, sspa->rx_base + SSPA_SP); 72 79 } 73 80 74 81 static void mmp_sspa_rx_disable(struct sspa_priv *sspa) ··· 77 84 78 85 sspa_sp &= ~SSPA_SP_S_EN; 79 86 sspa_sp |= SSPA_SP_WEN; 80 - mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 87 + __raw_writel(sspa_sp, sspa->rx_base + SSPA_SP); 81 88 } 82 89 83 90 static int mmp_sspa_startup(struct snd_pcm_substream *substream, ··· 98 105 99 106 clk_disable_unprepare(sspa->clk); 100 107 clk_disable_unprepare(sspa->sysclk); 101 - 102 108 } 103 109 104 110 /* ··· 107 115 int clk_id, unsigned int freq, int dir) 108 116 { 109 117 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai); 118 + struct device *dev = cpu_dai->component->dev; 110 119 int ret = 0; 120 + 121 + if (dev->of_node) 122 + return -ENOTSUPP; 111 123 112 124 switch (clk_id) { 113 125 case MMP_SSPA_CLK_AUDIO: ··· 135 139 unsigned int freq_out) 136 140 { 137 141 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(cpu_dai); 142 + struct device *dev = cpu_dai->component->dev; 138 143 int ret = 0; 144 + 145 + if (dev->of_node) 146 + return -ENOTSUPP; 139 147 140 148 switch (pll_id) { 141 149 case MMP_SYSCLK: ··· 213 213 struct snd_soc_dai *dai) 214 214 { 215 215 struct sspa_priv *sspa = snd_soc_dai_get_drvdata(dai); 216 + struct device *dev = dai->component->dev; 216 217 u32 sspa_ctrl = sspa->ctrl; 217 218 int bits; 218 219 int bitval; ··· 239 238 return -EINVAL; 240 239 } 241 240 242 - if (params_channels(params) == 2) 241 + if (dev->of_node || params_channels(params) == 2) 243 242 sspa_ctrl |= SSPA_CTL_XPH; 244 243 245 244 sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; ··· 257 256 sspa->sp &= ~SSPA_TXSP_FPER_MASK; 258 257 sspa->sp |= SSPA_TXSP_FPER(bits * 2 - 1); 259 258 259 + if (dev->of_node) { 260 + clk_set_rate(sspa->clk, params_rate(params) * 261 + params_channels(params) * bits); 262 + } 263 + 260 264 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 261 - mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); 262 - mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1); 265 + __raw_writel(sspa_ctrl, sspa->tx_base + SSPA_CTL); 266 + __raw_writel(0x1, sspa->tx_base + SSPA_FIFO_UL); 263 267 } else { 264 - mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); 265 - mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0); 268 + __raw_writel(sspa_ctrl, sspa->rx_base + SSPA_CTL); 269 + __raw_writel(0x0, sspa->rx_base + SSPA_FIFO_UL); 266 270 } 267 271 268 272 return 0; ··· 416 410 pm_runtime_get_sync(component->dev); 417 411 418 412 /* we can only change the settings if the port is not in use */ 419 - if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) || 420 - (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) { 413 + if ((__raw_readl(sspa->tx_base + SSPA_SP) & SSPA_SP_S_EN) || 414 + (__raw_readl(sspa->rx_base + SSPA_SP) & SSPA_SP_S_EN)) { 421 415 dev_err(component->dev, 422 416 "can't change hardware dai format: stream is in use\n"); 423 417 return -EBUSY; 424 418 } 425 419 426 - mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp); 427 - mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa->sp); 420 + __raw_writel(sspa->sp, sspa->tx_base + SSPA_SP); 421 + __raw_writel(sspa->sp, sspa->rx_base + SSPA_SP); 428 422 429 423 sspa->sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH); 430 - mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp); 431 - mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa->sp); 424 + __raw_writel(sspa->sp, sspa->tx_base + SSPA_SP); 425 + __raw_writel(sspa->sp, sspa->rx_base + SSPA_SP); 432 426 433 427 /* 434 428 * FIXME: hw issue, for the tx serial port, ··· 437 431 * The master/slave mode has been set in the 438 432 * rx port. 439 433 */ 440 - mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa->sp & ~SSPA_SP_MSL); 434 + __raw_writel(sspa->sp & ~SSPA_SP_MSL, sspa->tx_base + SSPA_SP); 441 435 442 - mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa->ctrl); 443 - mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa->ctrl); 436 + __raw_writel(sspa->ctrl, sspa->tx_base + SSPA_CTL); 437 + __raw_writel(sspa->ctrl, sspa->rx_base + SSPA_CTL); 444 438 445 439 return 0; 446 440 } ··· 468 462 if (!sspa) 469 463 return -ENOMEM; 470 464 471 - sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0); 472 - if (IS_ERR(sspa->mmio_base)) 473 - return PTR_ERR(sspa->mmio_base); 465 + if (pdev->dev.of_node) { 466 + sspa->rx_base = devm_platform_ioremap_resource(pdev, 0); 467 + if (IS_ERR(sspa->rx_base)) 468 + return PTR_ERR(sspa->rx_base); 474 469 475 - sspa->clk = devm_clk_get(&pdev->dev, NULL); 476 - if (IS_ERR(sspa->clk)) 477 - return PTR_ERR(sspa->clk); 470 + sspa->tx_base = devm_platform_ioremap_resource(pdev, 1); 471 + if (IS_ERR(sspa->tx_base)) 472 + return PTR_ERR(sspa->tx_base); 478 473 479 - sspa->audio_clk = clk_get(NULL, "mmp-audio"); 480 - if (IS_ERR(sspa->audio_clk)) 481 - return PTR_ERR(sspa->audio_clk); 474 + sspa->clk = devm_clk_get(&pdev->dev, "bitclk"); 475 + if (IS_ERR(sspa->clk)) 476 + return PTR_ERR(sspa->clk); 482 477 483 - sspa->sysclk = clk_get(NULL, "mmp-sysclk"); 484 - if (IS_ERR(sspa->sysclk)) { 485 - clk_put(sspa->audio_clk); 486 - return PTR_ERR(sspa->sysclk); 478 + sspa->audio_clk = devm_clk_get(&pdev->dev, "audio"); 479 + if (IS_ERR(sspa->audio_clk)) 480 + return PTR_ERR(sspa->audio_clk); 481 + } else { 482 + struct resource *res; 483 + 484 + res = platform_get_resource(pdev, IORESOURCE_IO, 0); 485 + if (res == NULL) 486 + return -ENODEV; 487 + 488 + sspa->rx_base = devm_ioremap(&pdev->dev, res->start, 0x30); 489 + if (IS_ERR(sspa->rx_base)) 490 + return PTR_ERR(sspa->rx_base); 491 + 492 + sspa->tx_base = devm_ioremap(&pdev->dev, 493 + res->start + 0x80, 0x30); 494 + if (IS_ERR(sspa->tx_base)) 495 + return PTR_ERR(sspa->tx_base); 496 + 497 + sspa->clk = devm_clk_get(&pdev->dev, NULL); 498 + if (IS_ERR(sspa->clk)) 499 + return PTR_ERR(sspa->clk); 500 + 501 + sspa->audio_clk = clk_get(NULL, "mmp-audio"); 502 + if (IS_ERR(sspa->audio_clk)) 503 + return PTR_ERR(sspa->audio_clk); 504 + 505 + sspa->sysclk = clk_get(NULL, "mmp-sysclk"); 506 + if (IS_ERR(sspa->sysclk)) { 507 + clk_put(sspa->audio_clk); 508 + return PTR_ERR(sspa->sysclk); 509 + } 487 510 } 488 511 pm_runtime_enable(&pdev->dev); 489 512 clk_prepare_enable(sspa->audio_clk); ··· 521 486 sspa->playback_dma_data.maxburst = 4; 522 487 sspa->capture_dma_data.maxburst = 4; 523 488 /* You know, these addresses are actually ignored. */ 524 - sspa->playback_dma_data.addr = SSPA_TXD; 525 - sspa->capture_dma_data.addr = SSPA_RXD; 489 + sspa->capture_dma_data.addr = SSPA_D; 490 + sspa->playback_dma_data.addr = 0x80 + SSPA_D; 526 491 527 492 if (pdev->dev.of_node) { 528 493 int ret; ··· 543 508 544 509 clk_disable_unprepare(sspa->audio_clk); 545 510 pm_runtime_disable(&pdev->dev); 511 + 512 + if (pdev->dev.of_node) 513 + return 0; 514 + 546 515 clk_put(sspa->audio_clk); 547 516 clk_put(sspa->sysclk); 548 517 return 0; 549 518 } 550 519 520 + #ifdef CONFIG_OF 521 + static const struct of_device_id mmp_sspa_of_match[] = { 522 + { .compatible = "marvell,mmp-sspa" }, 523 + {}, 524 + }; 525 + 526 + MODULE_DEVICE_TABLE(of, mmp_sspa_of_match); 527 + #endif 528 + 551 529 static struct platform_driver asoc_mmp_sspa_driver = { 552 530 .driver = { 553 531 .name = "mmp-sspa-dai", 532 + .of_match_table = of_match_ptr(mmp_sspa_of_match), 554 533 }, 555 534 .probe = asoc_mmp_sspa_probe, 556 535 .remove = asoc_mmp_sspa_remove,
+9 -19
sound/soc/pxa/mmp-sspa.h
··· 10 10 /* 11 11 * SSPA Registers 12 12 */ 13 - #define SSPA_RXD (0x00) 14 - #define SSPA_RXID (0x04) 15 - #define SSPA_RXCTL (0x08) 16 - #define SSPA_RXSP (0x0c) 17 - #define SSPA_RXFIFO_UL (0x10) 18 - #define SSPA_RXINT_MASK (0x14) 19 - #define SSPA_RXC (0x18) 20 - #define SSPA_RXFIFO_NOFS (0x1c) 21 - #define SSPA_RXFIFO_SIZE (0x20) 22 - 23 - #define SSPA_TXD (0x80) 24 - #define SSPA_TXID (0x84) 25 - #define SSPA_TXCTL (0x88) 26 - #define SSPA_TXSP (0x8c) 27 - #define SSPA_TXFIFO_LL (0x90) 28 - #define SSPA_TXINT_MASK (0x94) 29 - #define SSPA_TXC (0x98) 30 - #define SSPA_TXFIFO_NOFS (0x9c) 31 - #define SSPA_TXFIFO_SIZE (0xa0) 13 + #define SSPA_D (0x00) 14 + #define SSPA_ID (0x04) 15 + #define SSPA_CTL (0x08) 16 + #define SSPA_SP (0x0c) 17 + #define SSPA_FIFO_UL (0x10) 18 + #define SSPA_INT_MASK (0x14) 19 + #define SSPA_C (0x18) 20 + #define SSPA_FIFO_NOFS (0x1c) 21 + #define SSPA_FIFO_SIZE (0x20) 32 22 33 23 /* SSPA Control Register */ 34 24 #define SSPA_CTL_XPH (1 << 31) /* Read Phase */