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

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: add Allwinner H616 audio codec support

Merge series from Ryan Walklin <ryan@testtoast.com>:

The Allwinner H616 has a playback-only audio codec, with a single stereo
or differential-mono line output. This patch series adds support for
the H616 (and H313/H618/H700/T507) SoC. Based on the Allwinner kernel
SDK driver, and tested on the H700.

+309 -42
+47 -6
Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
··· 22 22 - allwinner,sun8i-a23-codec 23 23 - allwinner,sun8i-h3-codec 24 24 - allwinner,sun8i-v3s-codec 25 + - allwinner,sun50i-h616-codec 25 26 26 27 reg: 27 28 maxItems: 1 ··· 41 40 - const: codec 42 41 43 42 dmas: 44 - items: 45 - - description: RX DMA Channel 46 - - description: TX DMA Channel 43 + oneOf: 44 + - items: 45 + - description: RX DMA Channel 46 + - description: TX DMA Channel 47 + - items: 48 + - description: TX DMA Channel 47 49 48 50 dma-names: 49 - items: 50 - - const: rx 51 - - const: tx 51 + oneOf: 52 + - items: 53 + - const: rx 54 + - const: tx 55 + - items: 56 + - const: tx 52 57 53 58 resets: 54 59 maxItems: 1 ··· 235 228 - Line Out 236 229 - Mic 237 230 - Speaker 231 + 232 + - if: 233 + properties: 234 + compatible: 235 + enum: 236 + - allwinner,sun50i-h616-codec 237 + 238 + then: 239 + properties: 240 + allwinner,audio-routing: 241 + items: 242 + enum: 243 + - LINEOUT 244 + - Line Out 245 + 246 + dmas: 247 + items: 248 + - description: TX DMA Channel 249 + 250 + dma-names: 251 + items: 252 + - const: tx 253 + 254 + else: 255 + properties: 256 + dmas: 257 + items: 258 + - description: RX DMA Channel 259 + - description: TX DMA Channel 260 + 261 + dma-names: 262 + items: 263 + - const: rx 264 + - const: tx 238 265 239 266 unevaluatedProperties: false 240 267
+262 -36
sound/soc/sunxi/sun4i-codec.c
··· 226 226 #define SUN8I_H3_CODEC_DAC_DBG (0x48) 227 227 #define SUN8I_H3_CODEC_ADC_DBG (0x4c) 228 228 229 + /* H616 specific registers */ 230 + #define SUN50I_H616_CODEC_DAC_FIFOC (0x10) 231 + 232 + #define SUN50I_DAC_FIFO_STA (0x14) 233 + #define SUN50I_DAC_TXE_INT (3) 234 + #define SUN50I_DAC_TXU_INT (2) 235 + #define SUN50I_DAC_TXO_INT (1) 236 + 237 + #define SUN50I_DAC_CNT (0x24) 238 + #define SUN50I_DAC_DG_REG (0x28) 239 + #define SUN50I_DAC_DAP_CTL (0xf0) 240 + 241 + #define SUN50I_H616_DAC_AC_DAC_REG (0x310) 242 + #define SUN50I_H616_DAC_LEN (15) 243 + #define SUN50I_H616_DAC_REN (14) 244 + #define SUN50I_H616_LINEOUTL_EN (13) 245 + #define SUN50I_H616_LMUTE (12) 246 + #define SUN50I_H616_LINEOUTR_EN (11) 247 + #define SUN50I_H616_RMUTE (10) 248 + #define SUN50I_H616_RSWITCH (9) 249 + #define SUN50I_H616_RAMPEN (8) 250 + #define SUN50I_H616_LINEOUTL_SEL (6) 251 + #define SUN50I_H616_LINEOUTR_SEL (5) 252 + #define SUN50I_H616_LINEOUT_VOL (0) 253 + 254 + #define SUN50I_H616_DAC_AC_MIXER_REG (0x314) 255 + #define SUN50I_H616_LMIX_LDAC (21) 256 + #define SUN50I_H616_LMIX_RDAC (20) 257 + #define SUN50I_H616_RMIX_RDAC (17) 258 + #define SUN50I_H616_RMIX_LDAC (16) 259 + #define SUN50I_H616_LMIXEN (11) 260 + #define SUN50I_H616_RMIXEN (10) 261 + 262 + #define SUN50I_H616_DAC_AC_RAMP_REG (0x31c) 263 + #define SUN50I_H616_RAMP_STEP (4) 264 + #define SUN50I_H616_RDEN (0) 265 + 229 266 /* TODO H3 DAP (Digital Audio Processing) bits */ 230 267 231 268 struct sun4i_codec { ··· 275 238 276 239 /* ADC_FIFOC register is at different offset on different SoCs */ 277 240 struct regmap_field *reg_adc_fifoc; 241 + /* DAC_FIFOC register is at different offset on different SoCs */ 242 + struct regmap_field *reg_dac_fifoc; 278 243 279 244 struct snd_dmaengine_dai_dma_data capture_dma_data; 280 245 struct snd_dmaengine_dai_dma_data playback_dma_data; ··· 285 246 static void sun4i_codec_start_playback(struct sun4i_codec *scodec) 286 247 { 287 248 /* Flush TX FIFO */ 288 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 289 - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 249 + regmap_field_set_bits(scodec->reg_dac_fifoc, 250 + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 290 251 291 252 /* Enable DAC DRQ */ 292 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 293 - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); 253 + regmap_field_set_bits(scodec->reg_dac_fifoc, 254 + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); 294 255 } 295 256 296 257 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) 297 258 { 298 259 /* Disable DAC DRQ */ 299 - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 300 - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); 260 + regmap_field_clear_bits(scodec->reg_dac_fifoc, 261 + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); 301 262 } 302 263 303 264 static void sun4i_codec_start_capture(struct sun4i_codec *scodec) ··· 395 356 u32 val; 396 357 397 358 /* Flush the TX FIFO */ 398 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 399 - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 359 + regmap_field_set_bits(scodec->reg_dac_fifoc, 360 + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); 400 361 401 362 /* Set TX FIFO Empty Trigger Level */ 402 - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 403 - 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, 404 - 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); 363 + regmap_field_update_bits(scodec->reg_dac_fifoc, 364 + 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, 365 + 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); 405 366 406 367 if (substream->runtime->rate > 32000) 407 368 /* Use 64 bits FIR filter */ ··· 410 371 /* Use 32 bits FIR filter */ 411 372 val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION); 412 373 413 - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 414 - BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), 415 - val); 374 + regmap_field_update_bits(scodec->reg_dac_fifoc, 375 + BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), 376 + val); 416 377 417 378 /* Send zeros when we have an underrun */ 418 - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 419 - BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); 379 + regmap_field_clear_bits(scodec->reg_dac_fifoc, 380 + BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); 420 381 421 382 return 0; 422 383 }; ··· 549 510 u32 val; 550 511 551 512 /* Set DAC sample rate */ 552 - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 553 - 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, 554 - hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); 513 + regmap_field_update_bits(scodec->reg_dac_fifoc, 514 + 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, 515 + hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); 555 516 556 517 /* Set the number of channels we want to use */ 557 518 if (params_channels(params) == 1) ··· 559 520 else 560 521 val = 0; 561 522 562 - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 563 - BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), 564 - val); 523 + regmap_field_update_bits(scodec->reg_dac_fifoc, 524 + BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), 525 + val); 565 526 566 527 /* Set the number of sample bits to either 16 or 24 bits */ 567 528 if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { 568 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 569 - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); 529 + regmap_field_set_bits(scodec->reg_dac_fifoc, 530 + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); 570 531 571 532 /* Set TX FIFO mode to padding the LSBs with 0 */ 572 - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 573 - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); 533 + regmap_field_clear_bits(scodec->reg_dac_fifoc, 534 + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); 574 535 575 536 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 576 537 } else { 577 - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 578 - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); 538 + regmap_field_clear_bits(scodec->reg_dac_fifoc, 539 + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); 579 540 580 541 /* Set TX FIFO mode to repeat the MSB */ 581 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 582 - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); 542 + regmap_field_set_bits(scodec->reg_dac_fifoc, 543 + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); 583 544 584 545 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 585 546 } ··· 626 587 * Stop issuing DRQ when we have room for less than 16 samples 627 588 * in our TX FIFO 628 589 */ 629 - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, 630 - 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); 590 + regmap_field_set_bits(scodec->reg_dac_fifoc, 591 + 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); 631 592 632 593 return clk_prepare_enable(scodec->clk_module); 633 594 } ··· 1557 1518 return card; 1558 1519 }; 1559 1520 1521 + static const struct snd_kcontrol_new sun50i_h616_codec_codec_controls[] = { 1522 + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, 1523 + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, 1524 + sun6i_codec_dvol_scale), 1525 + SOC_SINGLE_TLV("Line Out Playback Volume", 1526 + SUN50I_H616_DAC_AC_DAC_REG, 1527 + SUN50I_H616_LINEOUT_VOL, 0x1f, 0, 1528 + sun6i_codec_lineout_vol_scale), 1529 + SOC_DOUBLE("Line Out Playback Switch", 1530 + SUN50I_H616_DAC_AC_DAC_REG, 1531 + SUN50I_H616_LINEOUTL_EN, 1532 + SUN50I_H616_LINEOUTR_EN, 1, 0), 1533 + }; 1534 + 1535 + static const struct snd_kcontrol_new sun50i_h616_codec_mixer_controls[] = { 1536 + SOC_DAPM_DOUBLE("DAC Playback Switch", 1537 + SUN50I_H616_DAC_AC_MIXER_REG, 1538 + SUN50I_H616_LMIX_LDAC, 1539 + SUN50I_H616_RMIX_RDAC, 1, 0), 1540 + SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", 1541 + SUN50I_H616_DAC_AC_MIXER_REG, 1542 + SUN50I_H616_LMIX_RDAC, 1543 + SUN50I_H616_RMIX_LDAC, 1, 0), 1544 + }; 1545 + 1546 + static SOC_ENUM_DOUBLE_DECL(sun50i_h616_codec_lineout_src_enum, 1547 + SUN50I_H616_DAC_AC_DAC_REG, 1548 + SUN50I_H616_LINEOUTL_SEL, 1549 + SUN50I_H616_LINEOUTR_SEL, 1550 + sun6i_codec_lineout_src_enum_text); 1551 + 1552 + static const struct snd_kcontrol_new sun50i_h616_codec_lineout_src[] = { 1553 + SOC_DAPM_ENUM("Line Out Source Playback Route", 1554 + sun50i_h616_codec_lineout_src_enum), 1555 + }; 1556 + 1557 + static const struct snd_soc_dapm_widget sun50i_h616_codec_codec_widgets[] = { 1558 + /* Digital parts of the DACs */ 1559 + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, 1560 + SUN4I_CODEC_DAC_DPC_EN_DA, 0, 1561 + NULL, 0), 1562 + 1563 + /* Analog parts of the DACs */ 1564 + SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", 1565 + SUN50I_H616_DAC_AC_DAC_REG, 1566 + SUN50I_H616_DAC_LEN, 0), 1567 + SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", 1568 + SUN50I_H616_DAC_AC_DAC_REG, 1569 + SUN50I_H616_DAC_REN, 0), 1570 + 1571 + /* Mixers */ 1572 + SOC_MIXER_ARRAY("Left Mixer", SUN50I_H616_DAC_AC_MIXER_REG, 1573 + SUN50I_H616_LMIXEN, 0, 1574 + sun50i_h616_codec_mixer_controls), 1575 + SOC_MIXER_ARRAY("Right Mixer", SUN50I_H616_DAC_AC_MIXER_REG, 1576 + SUN50I_H616_RMIXEN, 0, 1577 + sun50i_h616_codec_mixer_controls), 1578 + 1579 + /* Line Out path */ 1580 + SND_SOC_DAPM_MUX("Line Out Source Playback Route", 1581 + SND_SOC_NOPM, 0, 0, sun50i_h616_codec_lineout_src), 1582 + SND_SOC_DAPM_OUT_DRV("Line Out Ramp Controller", 1583 + SUN50I_H616_DAC_AC_RAMP_REG, 1584 + SUN50I_H616_RDEN, 0, NULL, 0), 1585 + SND_SOC_DAPM_OUTPUT("LINEOUT"), 1586 + }; 1587 + 1588 + static const struct snd_soc_component_driver sun50i_h616_codec_codec = { 1589 + .controls = sun50i_h616_codec_codec_controls, 1590 + .num_controls = ARRAY_SIZE(sun50i_h616_codec_codec_controls), 1591 + .dapm_widgets = sun50i_h616_codec_codec_widgets, 1592 + .num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_codec_widgets), 1593 + .idle_bias_on = 1, 1594 + .use_pmdown_time = 1, 1595 + .endianness = 1, 1596 + }; 1597 + 1598 + static const struct snd_kcontrol_new sun50i_h616_card_controls[] = { 1599 + SOC_DAPM_PIN_SWITCH("LINEOUT"), 1600 + }; 1601 + 1602 + static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = { 1603 + SND_SOC_DAPM_LINE("Line Out", NULL), 1604 + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), 1605 + }; 1606 + 1607 + /* Connect digital side enables to analog side widgets */ 1608 + static const struct snd_soc_dapm_route sun50i_h616_codec_card_routes[] = { 1609 + /* DAC Routes */ 1610 + { "Left DAC", NULL, "DAC Enable" }, 1611 + { "Right DAC", NULL, "DAC Enable" }, 1612 + 1613 + /* Left Mixer Routes */ 1614 + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, 1615 + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, 1616 + 1617 + /* Right Mixer Routes */ 1618 + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, 1619 + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, 1620 + 1621 + /* Line Out Routes */ 1622 + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, 1623 + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, 1624 + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, 1625 + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, 1626 + { "Line Out Ramp Controller", NULL, "Line Out Source Playback Route" }, 1627 + { "LINEOUT", NULL, "Line Out Ramp Controller" }, 1628 + }; 1629 + 1630 + static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev) 1631 + { 1632 + struct snd_soc_card *card; 1633 + int ret; 1634 + 1635 + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 1636 + if (!card) 1637 + return ERR_PTR(-ENOMEM); 1638 + 1639 + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); 1640 + if (!card->dai_link) 1641 + return ERR_PTR(-ENOMEM); 1642 + 1643 + card->dai_link->playback_only = true; 1644 + card->dai_link->capture_only = false; 1645 + 1646 + card->dev = dev; 1647 + card->owner = THIS_MODULE; 1648 + card->name = "H616 Audio Codec"; 1649 + card->driver_name = "sun4i-codec"; 1650 + card->controls = sun50i_h616_card_controls; 1651 + card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls); 1652 + card->dapm_widgets = sun50i_h616_codec_card_dapm_widgets; 1653 + card->num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_card_dapm_widgets); 1654 + card->dapm_routes = sun50i_h616_codec_card_routes; 1655 + card->num_dapm_routes = ARRAY_SIZE(sun50i_h616_codec_card_routes); 1656 + card->fully_routed = true; 1657 + 1658 + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); 1659 + if (ret) 1660 + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); 1661 + 1662 + return card; 1663 + }; 1664 + 1560 1665 static const struct regmap_config sun4i_codec_regmap_config = { 1561 1666 .reg_bits = 32, 1562 1667 .reg_stride = 4, ··· 1743 1560 .max_register = SUN8I_H3_CODEC_ADC_DBG, 1744 1561 }; 1745 1562 1563 + static const struct regmap_config sun50i_h616_codec_regmap_config = { 1564 + .reg_bits = 32, 1565 + .reg_stride = 4, 1566 + .val_bits = 32, 1567 + .max_register = SUN50I_H616_DAC_AC_RAMP_REG, 1568 + .cache_type = REGCACHE_NONE, 1569 + }; 1570 + 1746 1571 struct sun4i_codec_quirks { 1747 1572 const struct regmap_config *regmap_config; 1748 1573 const struct snd_soc_component_driver *codec; 1749 1574 struct snd_soc_card * (*create_card)(struct device *dev); 1750 1575 struct reg_field reg_adc_fifoc; /* used for regmap_field */ 1576 + struct reg_field reg_dac_fifoc; /* used for regmap_field */ 1751 1577 unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ 1752 1578 unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ 1753 1579 bool has_reset; 1580 + bool playback_only; 1754 1581 }; 1755 1582 1756 1583 static const struct sun4i_codec_quirks sun4i_codec_quirks = { ··· 1768 1575 .codec = &sun4i_codec_codec, 1769 1576 .create_card = sun4i_codec_create_card, 1770 1577 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), 1578 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1771 1579 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 1772 1580 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, 1773 1581 }; ··· 1778 1584 .codec = &sun6i_codec_codec, 1779 1585 .create_card = sun6i_codec_create_card, 1780 1586 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 1587 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1781 1588 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 1782 1589 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 1783 1590 .has_reset = true, ··· 1789 1594 .codec = &sun7i_codec_codec, 1790 1595 .create_card = sun4i_codec_create_card, 1791 1596 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), 1597 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1792 1598 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 1793 1599 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, 1794 1600 }; ··· 1799 1603 .codec = &sun8i_a23_codec_codec, 1800 1604 .create_card = sun8i_a23_codec_create_card, 1801 1605 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 1606 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1802 1607 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, 1803 1608 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 1804 1609 .has_reset = true, ··· 1815 1618 .codec = &sun8i_a23_codec_codec, 1816 1619 .create_card = sun8i_h3_codec_create_card, 1817 1620 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 1621 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1818 1622 .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, 1819 1623 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 1820 1624 .has_reset = true, ··· 1830 1632 .codec = &sun8i_a23_codec_codec, 1831 1633 .create_card = sun8i_v3s_codec_create_card, 1832 1634 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), 1635 + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), 1833 1636 .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, 1834 1637 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, 1638 + .has_reset = true, 1639 + }; 1640 + 1641 + static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = { 1642 + .regmap_config = &sun50i_h616_codec_regmap_config, 1643 + .codec = &sun50i_h616_codec_codec, 1644 + .create_card = sun50i_h616_codec_create_card, 1645 + .reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31), 1646 + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, 1835 1647 .has_reset = true, 1836 1648 }; 1837 1649 ··· 1869 1661 { 1870 1662 .compatible = "allwinner,sun8i-v3s-codec", 1871 1663 .data = &sun8i_v3s_codec_quirks, 1664 + }, 1665 + { 1666 + .compatible = "allwinner,sun50i-h616-codec", 1667 + .data = &sun50i_h616_codec_quirks, 1872 1668 }, 1873 1669 {} 1874 1670 }; ··· 1951 1739 return ret; 1952 1740 } 1953 1741 1742 + scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, 1743 + scodec->regmap, 1744 + quirks->reg_dac_fifoc); 1745 + if (IS_ERR(scodec->reg_dac_fifoc)) { 1746 + ret = PTR_ERR(scodec->reg_dac_fifoc); 1747 + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", 1748 + ret); 1749 + return ret; 1750 + } 1751 + 1954 1752 /* Enable the bus clock */ 1955 1753 if (clk_prepare_enable(scodec->clk_apb)) { 1956 1754 dev_err(&pdev->dev, "Failed to enable the APB clock\n"); ··· 1982 1760 scodec->playback_dma_data.maxburst = 8; 1983 1761 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 1984 1762 1985 - /* DMA configuration for RX FIFO */ 1986 - scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; 1987 - scodec->capture_dma_data.maxburst = 8; 1988 - scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 1763 + if (!quirks->playback_only) { 1764 + /* DMA configuration for RX FIFO */ 1765 + scodec->capture_dma_data.addr = res->start + 1766 + quirks->reg_adc_rxdata; 1767 + scodec->capture_dma_data.maxburst = 8; 1768 + scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 1769 + } 1989 1770 1990 1771 ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, 1991 1772 &sun4i_codec_dai, 1); ··· 2062 1837 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); 2063 1838 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 2064 1839 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); 1840 + MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com"); 2065 1841 MODULE_LICENSE("GPL");