Commit 0723ab4a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-4.7-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull more sound updates from Takashi Iwai:
 "This is the second update round for 4.7-rc1.  Most of changes are
  about the pending ASoC updates and fixes, including a few new drivers.
  Below are some highlights:

  ASoC:
   - New drivers for MAX98371 and TAS5720
   - SPI support for TLV320AIC32x4, along with the module split
   - TDM support for STI Uniperf IPs
   - Remaining topology API fixes / updates

  HDA:
   - A couple of Dell quirks and new Realtek codec support"

* tag 'sound-4.7-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (63 commits)
  ALSA: hda - Fix headset mic detection problem for one Dell machine
  spi: spi-ep93xx: Fix the PTR_ERR() argument
  ALSA: hda/realtek - Add support for ALC295/ALC3254
  ASoC: kirkwood: fix build failure
  ALSA: hda - Fix headphone noise on Dell XPS 13 9360
  ASoC: ak4642: Enable cache usage to fix crashes on resume
  ASoC: twl6040: Disconnect AUX output pads on digital mute
  ASoC: tlv320aic32x4: Properly implement the positive and negative pins into the mixers
  rcar: src: skip disabled-SRC nodes
  ASoC: max98371 Remove duplicate entry in max98371_reg
  ASoC: twl6040: Select LPPLL during standby
  ASoC: rsnd: don't use prohibited number to PDMACHCRn.SRS
  ASoC: simple-card: Add pm callbacks to platform driver
  ASoC: pxa: Fix module autoload for platform drivers
  ASoC: topology: Fix memory leak in widget creation
  ASoC: Add max98371 codec driver
  ASoC: rsnd: count .probe/.remove for rsnd_mod_call()
  ASoC: topology: Check size mismatch of ABI objects before parsing
  ASoC: topology: Check failure to create a widget
  ASoC: add support for TAS5720 digital amplifier
  ...
parents 9ba55cf7 eb4606e6
max98371 codec
This device supports I2C mode only.
Required properties:
- compatible : "maxim,max98371"
- reg : The chip select number on the I2C bus
Example:
&i2c {
max98371: max98371@0x31 {
compatible = "maxim,max98371";
reg = <0x31>;
};
};
MT8173 with RT5650 RT5676 CODECS
MT8173 with RT5650 RT5676 CODECS and HDMI via I2S
Required properties:
- compatible : "mediatek,mt8173-rt5650-rt5676"
- mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
and of the hdmi encoder node
- mediatek,platform: the phandle of MT8173 ASoC platform
Example:
sound {
compatible = "mediatek,mt8173-rt5650-rt5676";
mediatek,audio-codec = <&rt5650 &rt5676>;
mediatek,audio-codec = <&rt5650 &rt5676 &hdmi0>;
mediatek,platform = <&afe>;
};
......@@ -5,11 +5,21 @@ Required properties:
- mediatek,audio-codec: the phandles of rt5650 codecs
- mediatek,platform: the phandle of MT8173 ASoC platform
Optional subnodes:
- codec-capture : the subnode of rt5650 codec capture
Required codec-capture subnode properties:
- sound-dai: audio codec dai name on capture path
<&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1)
<&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2)
Example:
sound {
compatible = "mediatek,mt8173-rt5650";
mediatek,audio-codec = <&rt5650>;
mediatek,platform = <&afe>;
codec-capture {
sound-dai = <&rt5650 1>;
};
};
......@@ -37,17 +37,18 @@ Required properties:
- dai-name: DAI name that describes the IP.
- IP mode: IP working mode depending on associated codec.
"HDMI" connected to HDMI codec and support IEC HDMI formats (player only).
"SPDIF" connected to SPDIF codec and support SPDIF formats (player only).
"PCM" PCM standard mode for I2S or TDM bus.
"TDM" TDM mode for TDM bus.
Required properties ("st,sti-uni-player" compatibility only):
- clocks: CPU_DAI IP clock source, listed in the same order than the
CPU_DAI properties.
- uniperiph-id: internal SOC IP instance ID.
- IP mode: IP working mode depending on associated codec.
"HDMI" connected to HDMI codec IP and IEC HDMI formats.
"SPDIF"connected to SPDIF codec and support SPDIF formats.
"PCM" PCM standard mode for I2S or TDM bus.
Optional properties:
- pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for
external codecs connection.
......@@ -56,6 +57,22 @@ Optional properties:
Example:
sti_uni_player1: sti-uni-player@1 {
compatible = "st,sti-uni-player";
status = "okay";
#sound-dai-cells = <0>;
st,syscfg = <&syscfg_core>;
clocks = <&clk_s_d0_flexgen CLK_PCM_1>;
reg = <0x8D81000 0x158>;
interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
dmas = <&fdma0 3 0 1>;
st,dai-name = "Uni Player #1 (I2S)";
dma-names = "tx";
st,uniperiph-id = <1>;
st,version = <5>;
st,mode = "TDM";
};
sti_uni_player2: sti-uni-player@2 {
compatible = "st,sti-uni-player";
status = "okay";
......@@ -65,7 +82,7 @@ Example:
reg = <0x8D82000 0x158>;
interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
dmas = <&fdma0 4 0 1>;
dai-name = "Uni Player #1 (DAC)";
dai-name = "Uni Player #2 (DAC)";
dma-names = "tx";
uniperiph-id = <2>;
version = <5>;
......@@ -82,7 +99,7 @@ Example:
interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
dmas = <&fdma0 7 0 1>;
dma-names = "tx";
dai-name = "Uni Player #1 (PIO)";
dai-name = "Uni Player #3 (SPDIF)";
uniperiph-id = <3>;
version = <5>;
mode = "SPDIF";
......@@ -99,6 +116,7 @@ Example:
dma-names = "rx";
dai-name = "Uni Reader #1 (HDMI RX)";
version = <3>;
st,mode = "PCM";
};
2) sti-sas-codec: internal audio codec IPs driver
......@@ -152,4 +170,20 @@ Example of audio card declaration:
sound-dai = <&sti_sasg_codec 0>;
};
};
simple-audio-card,dai-link@2 {
/* TDM playback */
format = "left_j";
frame-inversion = <1>;
cpu {
sound-dai = <&sti_uni_player1>;
dai-tdm-slot-num = <16>;
dai-tdm-slot-width = <16>;
dai-tdm-slot-tx-mask =
<1 1 1 1 0 0 0 0 0 0 1 1 0 0 1 1>;
};
codec {
sound-dai = <&sti_sasg_codec 3>;
};
};
};
Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers
The codec is controlled through an I2C interface. It also has two other
signals that can be wired up to GPIOs: reset (strongly recommended), and
......@@ -6,7 +6,11 @@ powerdown (optional).
Required properties:
- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
- compatible: should be one of the following:
- "ti,tas5711",
- "ti,tas5717",
- "ti,tas5719",
- "ti,tas5721"
- reg: The I2C address of the device
- #sound-dai-cells: must be equal to 0
......@@ -25,6 +29,8 @@ Optional properties:
- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
- DRVDD-supply: regulator phandle for the DRVDD supply (5721)
- PVDD-supply: regulator phandle for the PVDD supply (5721)
Example:
......
Texas Instruments TAS5720 Mono Audio amplifier
The TAS5720 serial control bus communicates through the I2C protocol only. The
serial bus is also used for periodic codec fault checking/reporting during
audio playback. For more product information please see the links below:
http://www.ti.com/product/TAS5720L
http://www.ti.com/product/TAS5720M
Required properties:
- compatible : "ti,tas5720"
- reg : I2C slave address
- dvdd-supply : phandle to a 3.3-V supply for the digital circuitry
- pvdd-supply : phandle to a supply used for the Class-D amp and the analog
Example:
tas5720: tas5720@6c {
status = "okay";
compatible = "ti,tas5720";
reg = <0x6c>;
dvdd-supply = <&vdd_3v3_reg>;
pvdd-supply = <&amp_supply_reg>;
};
......@@ -567,7 +567,7 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi)
txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV);
if (IS_ERR(txd)) {
ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM);
dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(rxd));
dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
msg->status = PTR_ERR(txd);
return;
}
......
......@@ -134,6 +134,7 @@
#define TWL6040_HFDACENA (1 << 0)
#define TWL6040_HFPGAENA (1 << 1)
#define TWL6040_HFDRVENA (1 << 4)
#define TWL6040_HFSWENA (1 << 6)
/* VIBCTLL/R (0x18/0x1A) fields */
......
......@@ -116,6 +116,14 @@
#define SND_SOC_TPLG_STREAM_PLAYBACK 0
#define SND_SOC_TPLG_STREAM_CAPTURE 1
/* vendor tuple types */
#define SND_SOC_TPLG_TUPLE_TYPE_UUID 0
#define SND_SOC_TPLG_TUPLE_TYPE_STRING 1
#define SND_SOC_TPLG_TUPLE_TYPE_BOOL 2
#define SND_SOC_TPLG_TUPLE_TYPE_BYTE 3
#define SND_SOC_TPLG_TUPLE_TYPE_WORD 4
#define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5
/*
* Block Header.
* This header precedes all object and object arrays below.
......@@ -132,6 +140,35 @@ struct snd_soc_tplg_hdr {
__le32 count; /* number of elements in block */
} __attribute__((packed));
/* vendor tuple for uuid */
struct snd_soc_tplg_vendor_uuid_elem {
__le32 token;
char uuid[16];
} __attribute__((packed));
/* vendor tuple for a bool/byte/short/word value */
struct snd_soc_tplg_vendor_value_elem {
__le32 token;
__le32 value;
} __attribute__((packed));
/* vendor tuple for string */
struct snd_soc_tplg_vendor_string_elem {
__le32 token;
char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
} __attribute__((packed));
struct snd_soc_tplg_vendor_array {
__le32 size; /* size in bytes of the array, including all elements */
__le32 type; /* SND_SOC_TPLG_TUPLE_TYPE_ */
__le32 num_elems; /* number of elements in array */
union {
struct snd_soc_tplg_vendor_uuid_elem uuid[0];
struct snd_soc_tplg_vendor_value_elem value[0];
struct snd_soc_tplg_vendor_string_elem string[0];
};
} __attribute__((packed));
/*
* Private data.
* All topology objects may have private data that can be used by the driver or
......@@ -139,7 +176,10 @@ struct snd_soc_tplg_hdr {
*/
struct snd_soc_tplg_private {
__le32 size; /* in bytes of private data */
char data[0];
union {
char data[0];
struct snd_soc_tplg_vendor_array array[0];
};
} __attribute__((packed));
/*
......@@ -383,7 +423,7 @@ struct snd_soc_tplg_pcm {
__le32 size; /* in bytes of this structure */
char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 pcm_id; /* unique ID - used to match */
__le32 pcm_id; /* unique ID - used to match with DAI link */
__le32 dai_id; /* unique ID - used to match */
__le32 playback; /* supports playback mode */
__le32 capture; /* supports capture mode */
......
......@@ -335,6 +335,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0283:
case 0x10ec0286:
case 0x10ec0288:
case 0x10ec0295:
case 0x10ec0298:
alc_update_coef_idx(codec, 0x10, 1<<9, 0);
break;
......@@ -907,6 +908,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
{ 0x10ec0298, 0x1028, 0, "ALC3266" },
{ 0x10ec0256, 0x1028, 0, "ALC3246" },
{ 0x10ec0225, 0x1028, 0, "ALC3253" },
{ 0x10ec0295, 0x1028, 0, "ALC3254" },
{ 0x10ec0670, 0x1025, 0, "ALC669X" },
{ 0x10ec0676, 0x1025, 0, "ALC679X" },
{ 0x10ec0282, 0x1043, 0, "ALC3229" },
......@@ -3697,6 +3699,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
alc_process_coef_fw(codec, coef0668);
break;
case 0x10ec0225:
case 0x10ec0295:
alc_process_coef_fw(codec, coef0225);
break;
}
......@@ -3797,6 +3800,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
break;
case 0x10ec0225:
case 0x10ec0295:
alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
alc_process_coef_fw(codec, coef0225);
......@@ -3854,6 +3858,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
switch (codec->core.vendor_id) {
case 0x10ec0225:
case 0x10ec0295:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0255:
......@@ -3957,6 +3962,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
alc_process_coef_fw(codec, coef0688);
break;
case 0x10ec0225:
case 0x10ec0295:
alc_process_coef_fw(codec, coef0225);
break;
}
......@@ -4038,6 +4044,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
alc_process_coef_fw(codec, coef0688);
break;
case 0x10ec0225:
case 0x10ec0295:
alc_process_coef_fw(codec, coef0225);
break;
}
......@@ -4121,6 +4128,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
is_ctia = (val & 0x1c02) == 0x1c02;
break;
case 0x10ec0225:
case 0x10ec0295:
alc_process_coef_fw(codec, coef0225);
msleep(800);
val = alc_read_coef_idx(codec, 0x46);
......@@ -5466,8 +5474,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
......@@ -5710,6 +5719,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
{0x14, 0x90170110},
{0x21, 0x02211020}),
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x14, 0x90170130},
{0x21, 0x02211040}),
SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60140},
{0x14, 0x90170110},
......@@ -6033,6 +6045,7 @@ static int patch_alc269(struct hda_codec *codec)
alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
break;
case 0x10ec0225:
case 0x10ec0295:
spec->codec_variant = ALC269_TYPE_ALC225;
break;
case 0x10ec0234:
......@@ -6979,6 +6992,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
......
......@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK5386
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_BT_SCO
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS35L32 if I2C
select SND_SOC_CS42L51_I2C if I2C
......@@ -64,7 +65,6 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DMIC
select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
......@@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
select SND_SOC_MAX98357A if GPIOLIB
select SND_SOC_MAX98371 if I2C
select SND_SOC_MAX9867 if I2C
select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX98926 if I2C
......@@ -126,12 +127,14 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C
select SND_SOC_TAS5720 if I2C
select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC31XX if I2C
select SND_SOC_TLV320AIC32X4 if I2C
select SND_SOC_TLV320AIC32X4_I2C if I2C
select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
......@@ -367,6 +370,9 @@ config SND_SOC_ALC5623
config SND_SOC_ALC5632
tristate
config SND_SOC_BT_SCO
tristate
config SND_SOC_CQ0093VC
tristate
......@@ -473,9 +479,6 @@ config SND_SOC_DA732X
config SND_SOC_DA9055
tristate
config SND_SOC_BT_SCO
tristate
config SND_SOC_DMIC
tristate
......@@ -529,6 +532,9 @@ config SND_SOC_MAX98095
config SND_SOC_MAX98357A
tristate
config SND_SOC_MAX98371
tristate
config SND_SOC_MAX9867
tristate
......@@ -748,9 +754,16 @@ config SND_SOC_TAS5086
depends on I2C
config SND_SOC_TAS571X
tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers"
depends on I2C
config SND_SOC_TAS5720
tristate "Texas Instruments TAS5720 Mono Audio amplifier"
depends on I2C
help
Enable support for Texas Instruments TAS5720L/M high-efficiency mono
Class-D audio power amplifiers.
config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C
......@@ -780,6 +793,16 @@ config SND_SOC_TLV320AIC31XX
config SND_SOC_TLV320AIC32X4
tristate
config SND_SOC_TLV320AIC32X4_I2C
tristate
depends on I2C
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC32X4_SPI
tristate
depends on SPI_MASTER
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC3X
tristate "Texas Instruments TLV320AIC3x CODECs"
depends on I2C
......@@ -920,7 +943,8 @@ config SND_SOC_WM8955
tristate
config SND_SOC_WM8960
tristate
tristate "Wolfson Microelectronics WM8960 CODEC"
depends on I2C
config SND_SOC_WM8961
tristate
......
......@@ -32,6 +32,7 @@ snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs42l51-objs := cs42l51.o
......@@ -55,7 +56,6 @@ snd-soc-da7218-objs := da7218.o
snd-soc-da7219-objs := da7219.o da7219-aad.o
snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-dmic-objs := dmic.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
......@@ -74,6 +74,7 @@ snd-soc-max98088-objs := max98088.o
snd-soc-max98090-objs := max98090.o
snd-soc-max98095-objs := max98095.o
snd-soc-max98357a-objs := max98357a.o
snd-soc-max98371-objs := max98371.o
snd-soc-max9867-objs := max9867.o
snd-soc-max98925-objs := max98925.o
snd-soc-max98926-objs := max98926.o
......@@ -131,6 +132,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tas5720-objs := tas5720.o
snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
......@@ -138,6 +140,8 @@ snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-ts3a227e-objs := ts3a227e.o
......@@ -243,6 +247,7 @@ obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
......@@ -266,7 +271,6 @@ obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o
obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
......@@ -339,6 +343,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
......@@ -346,6 +351,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
......
......@@ -560,6 +560,7 @@ static const struct regmap_config ak4642_regmap = {
.max_register = FIL1_3,
.reg_defaults = ak4642_reg,
.num_reg_defaults = NUM_AK4642_REG_DEFAULTS,
.cache_type = REGCACHE_RBTREE,
};
static const struct regmap_config ak4643_regmap = {
......@@ -568,6 +569,7 @@ static const struct regmap_config ak4643_regmap = {
.max_register = SPK_MS,
.reg_defaults = ak4643_reg,
.num_reg_defaults = ARRAY_SIZE(ak4643_reg),
.cache_type = REGCACHE_RBTREE,
};
static const struct regmap_config ak4648_regmap = {
......@@ -576,6 +578,7 @@ static const struct regmap_config ak4648_regmap = {
.max_register = EQ_FBEQE,
.reg_defaults = ak4648_reg,
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
.cache_type = REGCACHE_RBTREE,
};
static const struct ak4642_drvdata ak4642_drvdata = {
......
This diff is collapsed.
/*
* max98371.h -- MAX98371 ALSA SoC Audio driver
*
* Copyright 2011-2012 Maxim Integrated Products
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MAX98371_H
#define _MAX98371_H
#define MAX98371_IRQ_CLEAR1 0x01
#define MAX98371_IRQ_CLEAR2 0x02
#define MAX98371_IRQ_CLEAR3 0x03
#define MAX98371_DAI_CLK 0x10
#define MAX98371_DAI_BSEL_MASK 0xF
#define MAX98371_DAI_BSEL_32 2
#define MAX98371_DAI_BSEL_48 3
#define MAX98371_DAI_BSEL_64 4
#define MAX98371_SPK_SR 0x11
#define MAX98371_SPK_SR_MASK 0xF
#define MAX98371_SPK_SR_32 6
#define MAX98371_SPK_SR_44 7
#define MAX98371_SPK_SR_48 8
#define MAX98371_SPK_SR_88 10
#define MAX98371_SPK_SR_96 11
#define MAX98371_DAI_CHANNEL 0x15
#define MAX98371_CHANNEL_MASK 0x3
#define MAX98371_MONOMIX_SRC 0x18
#define MAX98371_MONOMIX_CFG 0x19
#define MAX98371_HPF 0x1C
#define MAX98371_MONOMIX_SRC_MASK 0xFF
#define MONOMIX_RX_0_1 ((0x1)<<(4))
#define M98371_DAI_CHANNEL_I2S 0x3
#define MAX98371_DIGITAL_GAIN 0x2D
#define MAX98371_DIGITAL_GAIN_WIDTH 0x7
#define MAX98371_GAIN 0x2E
#define MAX98371_GAIN_SHIFT 0x4
#define MAX98371_GAIN_WIDTH 0x4
#define MAX98371_DHT_MAX_WIDTH 4
#define MAX98371_FMT 0x14
#define MAX98371_CHANSZ_WIDTH 6
#define MAX98371_FMT_MASK ((0x3)<<(MAX98371_CHANSZ_WIDTH))
#define MAX98371_FMT_MODE_MASK ((0x7)<<(3))
#define MAX98371_DAI_LEFT ((0x1)<<(3))
#define MAX98371_DAI_RIGHT ((0x2)<<(3))
#define MAX98371_DAI_CHANSZ_16 ((1)<<(MAX98371_CHANSZ_WIDTH))
#define MAX98371_DAI_CHANSZ_24 ((2)<<(MAX98371_CHANSZ_WIDTH))
#define MAX98371_DAI_CHANSZ_32 ((3)<<(MAX98371_CHANSZ_WIDTH))
#define MAX98371_DHT 0x32
#define MAX98371_DHT_STEP 0x3
#define MAX98371_DHT_GAIN 0x31
#define MAX98371_DHT_GAIN_WIDTH 0x4
#define MAX98371_DHT_ROT_WIDTH 0x4
#define MAX98371_SPK_ENABLE 0x4A
#define MAX98371_GLOBAL_ENABLE 0x50
#define MAX98371_SOFT_RESET 0x51
#define MAX98371_VERSION 0xFF
struct max98371_priv {
struct regmap *regmap;
struct snd_soc_codec *codec;
};
#endif
......@@ -276,6 +276,8 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
} else {
*mic = false;
regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20);
regmap_update_bits(rt298->regmap,
RT298_CBJ_CTRL1, 0x0400, 0x0000);
}
} else {
regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
......@@ -482,6 +484,26 @@ static int rt298_adc_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
0x7080, 0x7000);
/* If MCLK doesn't exist, reset AD filter */
if (!(snd_soc_read(codec, RT298_VAD_CTRL) & 0x200)) {
pr_info("NO MCLK\n");
switch (nid) {
case RT298_ADC_IN1:
snd_soc_update_bits(codec,
RT298_D_FILTER_CTRL, 0x2, 0x2);
mdelay(10);
snd_soc_update_bits(codec,
RT298_D_FILTER_CTRL, 0x2, 0x0);
break;
case RT298_ADC_IN2:
snd_soc_update_bits(codec,
RT298_D_FILTER_CTRL, 0x4, 0x4);
mdelay(10);
snd_soc_update_bits(codec,
RT298_D_FILTER_CTRL, 0x4, 0x0);
break;
}
}
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec,
......@@ -520,30 +542,12 @@ static int rt298_mic1_event(struct snd_soc_dapm_widget *w,
return 0;
}
static int rt298_vref_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec,
RT298_CBJ_CTRL1, 0x0400, 0x0000);
mdelay(50);
break;
default:
return 0;
}
return 0;
}
static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1,
12, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1,
0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU),
0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2,
1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2,
......@@ -934,18 +938,9 @@ static int rt298_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_ON:
mdelay(30);
snd_soc_update_bits(codec,
RT298_CBJ_CTRL1, 0x0400, 0x0400);
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec,
RT298_SET_AUDIO_POWER, AC_PWRST_D3);
snd_soc_update_bits(codec,
RT298_CBJ_CTRL1, 0x0400, 0x0000);
break;
default:
......
......@@ -137,6 +137,7 @@
#define RT298_A_BIAS_CTRL2 0x02
#define RT298_POWER_CTRL1 0x03
#define RT298_A_BIAS_CTRL3 0x04
#define RT298_D_FILTER_CTRL 0x05
#define RT298_POWER_CTRL2 0x08
#define RT298_I2S_CTRL1 0x09
#define RT298_I2S_CTRL2 0x0a
......@@ -148,6 +149,7 @@
#define RT298_IRQ_CTRL 0x33
#define RT298_WIND_FILTER_CTRL 0x46
#define RT298_PLL_CTRL1 0x49
#define RT298_VAD_CTRL 0x4e
#define RT298_CBJ_CTRL1 0x4f
#define RT298_CBJ_CTRL2 0x50
#define RT298_PLL_CTRL 0x63
......
......@@ -1241,60 +1241,46 @@ static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
RT5677_AD_STO1_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 10:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
RT5677_AD_STO2_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 9:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
RT5677_AD_STO3_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 8:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
RT5677_AD_STO4_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 7:
regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
RT5677_AD_MONOL_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 6:
regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
RT5677_AD_MONOR_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
default:
break;
return 0;
}
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
return 0;
}
......
......@@ -4,6 +4,9 @@
* Copyright (C) 2015 Google, Inc.
* Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
*
* TAS5721 support:
* Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
......@@ -57,6 +60,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
case TAS571X_CH1_VOL_REG:
case TAS571X_CH2_VOL_REG:
return priv->chip->vol_reg_size;
case TAS571X_INPUT_MUX_REG:
case TAS571X_CH4_SRC_SELECT_REG:
case TAS571X_PWM_MUX_REG:
return 4;
default:
return 1;
}
......@@ -167,6 +174,23 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream,
TAS571X_SDI_FMT_MASK, val);
}
static int tas571x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u8 sysctl2;
int ret;
sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0;
ret = snd_soc_update_bits(codec,
TAS571X_SYS_CTRL_2_REG,
TAS571X_SYS_CTRL_2_SDN_MASK,
sysctl2);
usleep_range(1000, 2000);
return ret;
}
static int tas571x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
......@@ -214,6 +238,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops tas571x_dai_ops = {
.set_fmt = tas571x_set_dai_fmt,
.hw_params = tas571x_hw_params,
.digital_mute = tas571x_mute,
};
static const char *const tas5711_supply_names[] = {
......@@ -241,6 +266,26 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
1, 1),
};
static const struct regmap_range tas571x_readonly_regs_range[] = {
regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_DEV_ID_REG),
};
static const struct regmap_range tas571x_volatile_regs_range[] = {
regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_ERR_STATUS_REG),
regmap_reg_range(TAS571X_OSC_TRIM_REG, TAS571X_OSC_TRIM_REG),
};
static const struct regmap_access_table tas571x_write_regs = {
.no_ranges = tas571x_readonly_regs_range,
.n_no_ranges = ARRAY_SIZE(tas571x_readonly_regs_range),
};
static const struct regmap_access_table tas571x_volatile_regs = {
.yes_ranges = tas571x_volatile_regs_range,
.n_yes_ranges = ARRAY_SIZE(tas571x_volatile_regs_range),
};
static const struct reg_default tas5711_reg_defaults[] = {
{ 0x04, 0x05 },
{ 0x05, 0x40 },
......@@ -260,6 +305,8 @@ static const struct regmap_config tas5711_regmap_config = {
.reg_defaults = tas5711_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults),
.cache_type = REGCACHE_RBTREE,
.wr_table = &tas571x_write_regs,
.volatile_table = &tas571x_volatile_regs,
};
static const struct tas571x_chip tas5711_chip = {
......@@ -314,6 +361,8 @@ static const struct regmap_config tas5717_regmap_config = {
.reg_defaults = tas5717_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults),
.cache_type = REGCACHE_RBTREE,
.wr_table = &tas571x_write_regs,
.volatile_table = &tas571x_volatile_regs,
};
/* This entry is reused for tas5719 as the software interface is identical. */
......@@ -326,6 +375,77 @@ static const struct tas571x_chip tas5717_chip = {
.vol_reg_size = 2,
};
static const char *const tas5721_supply_names[] = {
"AVDD",
"DVDD",
"DRVDD",
"PVDD",
};
static const struct snd_kcontrol_new tas5721_controls[] = {
SOC_SINGLE_TLV("Master Volume",
TAS571X_MVOL_REG,
0, 0xff, 1, tas5711_volume_tlv),
SOC_DOUBLE_R_TLV("Speaker Volume",
TAS571X_CH1_VOL_REG,
TAS571X_CH2_VOL_REG,
0, 0xff, 1, tas5711_volume_tlv),
SOC_DOUBLE("Speaker Switch",
TAS571X_SOFT_MUTE_REG,
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
1, 1),
};
static const struct reg_default tas5721_reg_defaults[] = {
{TAS571X_CLK_CTRL_REG, 0x6c},
{TAS571X_DEV_ID_REG, 0x00},
{TAS571X_ERR_STATUS_REG, 0x00},
{TAS571X_SYS_CTRL_1_REG, 0xa0},
{TAS571X_SDI_REG, 0x05},
{TAS571X_SYS_CTRL_2_REG, 0x40},
{TAS571X_SOFT_MUTE_REG, 0x00},
{TAS571X_MVOL_REG, 0xff},
{TAS571X_CH1_VOL_REG, 0x30},
{TAS571X_CH2_VOL_REG, 0x30},
{TAS571X_CH3_VOL_REG, 0x30},
{TAS571X_VOL_CFG_REG, 0x91},
{TAS571X_MODULATION_LIMIT_REG, 0x02},
{TAS571X_IC_DELAY_CH1_REG, 0xac},
{TAS571X_IC_DELAY_CH2_REG, 0x54},
{TAS571X_IC_DELAY_CH3_REG, 0xac},
{TAS571X_IC_DELAY_CH4_REG, 0x54},
{TAS571X_PWM_CH_SDN_GROUP_REG, 0x30},
{TAS571X_START_STOP_PERIOD_REG, 0x0f},
{TAS571X_OSC_TRIM_REG, 0x82},
{TAS571X_BKND_ERR_REG, 0x02},
{TAS571X_INPUT_MUX_REG, 0x17772},
{TAS571X_CH4_SRC_SELECT_REG, 0x4303},
{TAS571X_PWM_MUX_REG, 0x1021345},
};
static const struct regmap_config tas5721_regmap_config = {
.reg_bits = 8,
.val_bits = 32,
.max_register = 0xff,
.reg_read = tas571x_reg_read,
.reg_write = tas571x_reg_write,
.reg_defaults = tas5721_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas5721_reg_defaults),
.cache_type = REGCACHE_RBTREE,
.wr_table = &tas571x_write_regs,
.volatile_table = &tas571x_volatile_regs,
};
static const struct tas571x_chip tas5721_chip = {
.supply_names = tas5721_supply_names,
.num_supply_names = ARRAY_SIZE(tas5721_supply_names),
.controls = tas5711_controls,
.num_controls = ARRAY_SIZE(tas5711_controls),
.regmap_config = &tas5721_regmap_config,
.vol_reg_size = 1,
};
static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
......@@ -386,11 +506,10 @@ static int tas571x_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, priv);
of_id = of_match_device(tas571x_of_match, dev);
if (!of_id) {
dev_err(dev, "Unknown device type\n");
return -EINVAL;
}
priv->chip = of_id->data;
if (of_id)
priv->chip = of_id->data;
else
priv->chip = (void *) id->driver_data;
priv->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
......@@ -445,10 +564,6 @@ static int tas571x_i2c_probe(struct i2c_client *client,
if (ret)
return ret;
ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG,
TAS571X_SYS_CTRL_2_SDN_MASK, 0);
if (ret)
return ret;
memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
priv->codec_driver.controls = priv->chip->controls;
......@@ -486,14 +601,16 @@ static const struct of_device_id tas571x_of_match[] = {
{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
{ .compatible = "ti,tas5721", .data = &tas5721_chip, },
{ }
};
MODULE_DEVICE_TABLE(of, tas571x_of_match);
static const struct i2c_device_id tas571x_i2c_id[] = {
{ "tas5711", 0 },
{ "tas5717", 0 },
{ "tas5719", 0 },
{ "tas5711", (kernel_ulong_t) &tas5711_chip },
{ "tas5717", (kernel_ulong_t) &tas5717_chip },
{ "tas5719", (kernel_ulong_t) &tas5717_chip },
{ "tas5721", (kernel_ulong_t) &tas5721_chip },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
......
......@@ -13,6 +13,10 @@
#define _TAS571X_H
/* device registers */
#define TAS571X_CLK_CTRL_REG 0x00
#define TAS571X_DEV_ID_REG 0x01
#define TAS571X_ERR_STATUS_REG 0x02
#define TAS571X_SYS_CTRL_1_REG 0x03
#define TAS571X_SDI_REG 0x04
#define TAS571X_SDI_FMT_MASK 0x0f
......@@ -27,7 +31,25 @@
#define TAS571X_MVOL_REG 0x07
#define TAS571X_CH1_VOL_REG 0x08
#define TAS571X_CH2_VOL_REG 0x09
#define TAS571X_CH3_VOL_REG 0x0a
#define TAS571X_VOL_CFG_REG 0x0e
#define TAS571X_MODULATION_LIMIT_REG 0x10
#define TAS571X_IC_DELAY_CH1_REG 0x11
#define TAS571X_IC_DELAY_CH2_REG 0x12
#define TAS571X_IC_DELAY_CH3_REG 0x13
#define TAS571X_IC_DELAY_CH4_REG 0x14
#define TAS571X_PWM_CH_SDN_GROUP_REG 0x19 /* N/A on TAS5717, TAS5719 */
#define TAS571X_PWM_CH1_SDN_MASK (1<<0)
#define TAS571X_PWM_CH2_SDN_SHIFT (1<<1)
#define TAS571X_PWM_CH3_SDN_SHIFT (1<<2)
#define TAS571X_PWM_CH4_SDN_SHIFT (1<<3)
#define TAS571X_START_STOP_PERIOD_REG 0x1a
#define TAS571X_OSC_TRIM_REG 0x1b
#define TAS571X_BKND_ERR_REG 0x1c
#define TAS571X_INPUT_MUX_REG 0x20
#define TAS571X_CH4_SRC_SELECT_REG 0x21
#define TAS571X_PWM_MUX_REG 0x25
#endif /* _TAS571X_H */
This diff is collapsed.
/*
* tas5720.h - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
*
* Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Andreas Dannenberg <dannenberg@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __TAS5720_H__
#define __TAS5720_H__
/* Register Address Map */
#define TAS5720_DEVICE_ID_REG 0x00
#define TAS5720_POWER_CTRL_REG 0x01
#define TAS5720_DIGITAL_CTRL1_REG 0x02
#define TAS5720_DIGITAL_CTRL2_REG 0x03
#define TAS5720_VOLUME_CTRL_REG 0x04
#define TAS5720_ANALOG_CTRL_REG 0x06
#define TAS5720_FAULT_REG 0x08
#define TAS5720_DIGITAL_CLIP2_REG 0x10
#define TAS5720_DIGITAL_CLIP1_REG 0x11
#define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG
/* TAS5720_DEVICE_ID_REG */
#define TAS5720_DEVICE_ID 0x01
/* TAS5720_POWER_CTRL_REG */
#define TAS5720_DIG_CLIP_MASK GENMASK(7, 2)
#define TAS5720_SLEEP BIT(1)
#define TAS5720_SDZ BIT(0)
/* TAS5720_DIGITAL_CTRL1_REG */
#define TAS5720_HPF_BYPASS BIT(7)
#define TAS5720_TDM_CFG_SRC BIT(6)
#define TAS5720_SSZ_DS BIT(3)
#define TAS5720_SAIF_RIGHTJ_24BIT (0x0)
#define TAS5720_SAIF_RIGHTJ_20BIT (0x1)
#define TAS5720_SAIF_RIGHTJ_18BIT (0x2)
#define TAS5720_SAIF_RIGHTJ_16BIT (0x3)
#define TAS5720_SAIF_I2S (0x4)
#define TAS5720_SAIF_LEFTJ (0x5)
#define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0)
/* TAS5720_DIGITAL_CTRL2_REG */
#define TAS5720_MUTE BIT(4)
#define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0)
/* TAS5720_ANALOG_CTRL_REG */
#define TAS5720_PWM_RATE_6_3_FSYNC (0x0 << 4)
#define TAS5720_PWM_RATE_8_4_FSYNC (0x1 << 4)
#define TAS5720_PWM_RATE_10_5_FSYNC (0x2 << 4)
#define TAS5720_PWM_RATE_12_6_FSYNC (0x3 << 4)
#define TAS5720_PWM_RATE_14_7_FSYNC (0x4 << 4)
#define TAS5720_PWM_RATE_16_8_FSYNC (0x5 << 4)
#define TAS5720_PWM_RATE_20_10_FSYNC (0x6 << 4)
#define TAS5720_PWM_RATE_24_12_FSYNC (0x7 << 4)
#define TAS5720_PWM_RATE_MASK GENMASK(6, 4)
#define TAS5720_ANALOG_GAIN_19_2DBV (0x0 << 2)
#define TAS5720_ANALOG_GAIN_20_7DBV (0x1 << 2)
#define TAS5720_ANALOG_GAIN_23_5DBV (0x2 << 2)
#define TAS5720_ANALOG_GAIN_26_3DBV (0x3 << 2)
#define TAS5720_ANALOG_GAIN_MASK GENMASK(3, 2)
#define TAS5720_ANALOG_GAIN_SHIFT (0x2)
/* TAS5720_FAULT_REG */
#define TAS5720_OC_THRESH_100PCT (0x0 << 4)
#define TAS5720_OC_THRESH_75PCT (0x1 << 4)
#define TAS5720_OC_THRESH_50PCT (0x2 << 4)
#define TAS5720_OC_THRESH_25PCT (0x3 << 4)
#define TAS5720_OC_THRESH_MASK GENMASK(5, 4)
#define TAS5720_CLKE BIT(3)
#define TAS5720_OCE BIT(2)
#define TAS5720_DCE BIT(1)
#define TAS5720_OTE BIT(0)
#define TAS5720_FAULT_MASK GENMASK(3, 0)
/* TAS5720_DIGITAL_CLIP1_REG */
#define TAS5720_CLIP1_MASK GENMASK(7, 2)
#define TAS5720_CLIP1_SHIFT (0x2)
#endif /* __TAS5720_H__ */
......@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
......@@ -1280,10 +1281,19 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id aic31xx_acpi_match[] = {
{ "10TI3100", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
static struct i2c_driver aic31xx_i2c_driver = {
.driver = {
.name = "tlv320aic31xx-codec",
.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
.acpi_match_table = ACPI_PTR(aic31xx_acpi_match),
},
.probe = aic31xx_i2c_probe,
.remove = aic31xx_i2c_remove,
......
/*
* linux/sound/soc/codecs/tlv320aic32x4-i2c.c
*
* Copyright 2011 NW Digital Radio
*
* Author: Jeremy McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "tlv320aic32x4.h"
static int aic32x4_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap *regmap;
struct regmap_config config;
config = aic32x4_regmap_config;
config.reg_bits = 8;
config.val_bits = 8;
regmap = devm_regmap_init_i2c(i2c, &config);
return aic32x4_probe(&i2c->dev, regmap);
}
static int aic32x4_i2c_remove(struct i2c_client *i2c)
{
return aic32x4_remove(&i2c->dev);
}
static const struct i2c_device_id aic32x4_i2c_id[] = {
{ "tlv320aic32x4", 0 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
static const struct of_device_id aic32x4_of_id[] = {
{ .compatible = "ti,tlv320aic32x4", },
{ /* senitel */ }
};
MODULE_DEVICE_TABLE(of, aic32x4_of_id);
static struct i2c_driver aic32x4_i2c_driver = {
.driver = {
.name = "tlv320aic32x4",
.of_match_table = aic32x4_of_id,
},
.probe = aic32x4_i2c_probe,
.remove = aic32x4_i2c_remove,
.id_table = aic32x4_i2c_id,
};
module_i2c_driver(aic32x4_i2c_driver);
MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C");
MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>");
MODULE_LICENSE("GPL");
/*
* linux/sound/soc/codecs/tlv320aic32x4-spi.c
*
* Copyright 2011 NW Digital Radio
*
* Author: Jeremy McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "tlv320aic32x4.h"
static int aic32x4_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
struct regmap_config config;
config = aic32x4_regmap_config;
config.reg_bits = 7;
config.pad_bits = 1;
config.val_bits = 8;
config.read_flag_mask = 0x01;
regmap = devm_regmap_init_spi(spi, &config);
return aic32x4_probe(&spi->dev, regmap);
}
static int aic32x4_spi_remove(struct spi_device *spi)
{
return aic32x4_remove(&spi->dev);
}
static const struct spi_device_id aic32x4_spi_id[] = {
{ "tlv320aic32x4", 0 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, aic32x4_spi_id);
static const struct of_device_id aic32x4_of_id[] = {
{ .compatible = "ti,tlv320aic32x4", },
{ /* senitel */ }
};
MODULE_DEVICE_TABLE(of, aic32x4_of_id);
static struct spi_driver aic32x4_spi_driver = {
.driver = {
.name = "tlv320aic32x4",
.owner = THIS_MODULE,
.of_match_table = aic32x4_of_id,
},
.probe = aic32x4_spi_probe,
.remove = aic32x4_spi_remove,
.id_table = aic32x4_spi_id,
};
module_spi_driver(aic32x4_spi_driver);
MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI");
MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -10,6 +10,13 @@
#ifndef _TLV320AIC32X4_H
#define _TLV320AIC32X4_H
struct device;
struct regmap_config;
extern const struct regmap_config aic32x4_regmap_config;
int aic32x4_probe(struct device *dev, struct regmap *regmap);
int aic32x4_remove(struct device *dev);
/* tlv320aic32x4 register space (in decimal to match datasheet) */
#define AIC32X4_PAGE1 128
......
......@@ -824,7 +824,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
{
struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int ret;
int ret = 0;
switch (level) {
case SND_SOC_BIAS_ON:
......@@ -832,12 +832,16 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (priv->codec_powered)
if (priv->codec_powered) {
/* Select low power PLL in standby */
ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL,
32768, 19200000);
break;
}
ret = twl6040_power(twl6040, 1);
if (ret)
return ret;
break;
priv->codec_powered = 1;
......@@ -853,7 +857,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
break;
}
return 0;
return ret;
}
static int twl6040_startup(struct snd_pcm_substream *substream,
......@@ -983,9 +987,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
if (mute) {
/* Power down drivers and DACs */
hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
TWL6040_HFDRVENA);
TWL6040_HFDRVENA | TWL6040_HFSWENA);
hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
TWL6040_HFDRVENA);
TWL6040_HFDRVENA | TWL6040_HFSWENA);
}
twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
......
......@@ -3793,9 +3793,8 @@ static int wm8962_runtime_resume(struct device *dev)
ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
wm8962->supplies);
if (ret != 0) {
dev_err(dev,
"Failed to enable supplies: %d\n", ret);
return ret;
dev_err(dev, "Failed to enable supplies: %d\n", ret);
goto disable_clock;
}
regcache_cache_only(wm8962->regmap, false);
......@@ -3833,6 +3832,10 @@ static int wm8962_runtime_resume(struct device *dev)
msleep(5);
return 0;
disable_clock:
clk_disable_unprepare(wm8962->pdata.mclk);
return ret;
}
static int wm8962_runtime_suspend(struct device *dev)
......
......@@ -16,9 +16,9 @@
#include <asm/types.h>
#include <sound/soc.h>
#define WM8962_SYSCLK_MCLK 1
#define WM8962_SYSCLK_FLL 2
#define WM8962_SYSCLK_PLL3 3
#define WM8962_SYSCLK_MCLK 0
#define WM8962_SYSCLK_FLL 1
#define WM8962_SYSCLK_PLL3 2
#define WM8962_FLL 1
......
......@@ -643,6 +643,7 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
static struct platform_driver asoc_simple_card = {
.driver = {
.name = "asoc-simple-card",
.pm = &snd_soc_pm_ops,
.of_match_table = asoc_simple_of_match,
},
.probe = asoc_simple_card_probe,
......
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
depends on HAS_DMA
help
Say Y or M if you want to add support for codecs attached to
the Kirkwood I2S interface. You will also need to select the
......
......@@ -43,6 +43,7 @@ config SND_SOC_MT8173_RT5650_RT5676
depends on SND_SOC_MEDIATEK && I2C
select SND_SOC_RT5645
select SND_SOC_RT5677
select SND_SOC_HDMI_CODEC
help
This adds ASoC driver for Mediatek MT8173 boards
with the RT5650 and RT5676 codecs.
......
......@@ -134,7 +134,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = {
enum {
DAI_LINK_PLAYBACK,
DAI_LINK_CAPTURE,
DAI_LINK_HDMI,
DAI_LINK_CODEC_I2S,
DAI_LINK_HDMI_I2S,
DAI_LINK_INTERCODEC
};
......@@ -161,6 +163,16 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.dynamic = 1,
.dpcm_capture = 1,
},
[DAI_LINK_HDMI] = {
.name = "HDMI",
.stream_name = "HDMI PCM",
.cpu_dai_name = "HDMI",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
.dpcm_playback = 1,
},
/* Back End DAI links */
[DAI_LINK_CODEC_I2S] = {
......@@ -177,6 +189,13 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.dpcm_playback = 1,
.dpcm_capture = 1,
},
[DAI_LINK_HDMI_I2S] = {
.name = "HDMI BE",
.cpu_dai_name = "HDMIO",
.no_pcm = 1,
.codec_dai_name = "i2s-hifi",
.dpcm_playback = 1,
},
/* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
[DAI_LINK_INTERCODEC] = {
.name = "rt5650_rt5676 intercodec",
......@@ -251,6 +270,14 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node =
mt8173_rt5650_rt5676_codecs[1].of_node;
mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node =
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
......
......@@ -85,12 +85,29 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
const char *codec_capture_dai = runtime->codec_dais[1]->name;
int ret;
rt5645_sel_asrc_clk_src(codec,
RT5645_DA_STEREO_FILTER |
RT5645_AD_STEREO_FILTER,
RT5645_DA_STEREO_FILTER,
RT5645_CLK_SEL_I2S1_ASRC);
if (!strcmp(codec_capture_dai, "rt5645-aif1")) {
rt5645_sel_asrc_clk_src(codec,
RT5645_AD_STEREO_FILTER,
RT5645_CLK_SEL_I2S1_ASRC);
} else if (!strcmp(codec_capture_dai, "rt5645-aif2")) {
rt5645_sel_asrc_clk_src(codec,
RT5645_AD_STEREO_FILTER,
RT5645_CLK_SEL_I2S2_ASRC);
} else {
dev_warn(card->dev,
"Only one dai codec found in DTS, enabled rt5645 AD filter\n");
rt5645_sel_asrc_clk_src(codec,
RT5645_AD_STEREO_FILTER,
RT5645_CLK_SEL_I2S1_ASRC);
}
/* enable jack detection */
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
......@@ -110,6 +127,11 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = {
{
/* Playback */
.dai_name = "rt5645-aif1",
},
{
/* Capture */
.dai_name = "rt5645-aif1",
},
};
......@@ -149,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
.cpu_dai_name = "I2S",
.no_pcm = 1,
.codecs = mt8173_rt5650_codecs,
.num_codecs = 1,
.num_codecs = 2,
.init = mt8173_rt5650_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
......@@ -177,6 +199,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &mt8173_rt5650_card;
struct device_node *platform_node;
struct device_node *np;
const char *codec_capture_dai;
int i, ret;
platform_node = of_parse_phandle(pdev->dev.of_node,
......@@ -199,6 +223,26 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
mt8173_rt5650_codecs[1].of_node = mt8173_rt5650_codecs[0].of_node;
if (of_find_node_by_name(platform_node, "codec-capture")) {
np = of_get_child_by_name(pdev->dev.of_node, "codec-capture");
if (!np) {
dev_err(&pdev->dev,
"%s: Can't find codec-capture DT node\n",
__func__);
return -EINVAL;
}
ret = snd_soc_of_get_dai_name(np, &codec_capture_dai);
if (ret < 0) {
dev_err(&pdev->dev,
"%s codec_capture_dai name fail %d\n",
__func__, ret);
return ret;
}
mt8173_rt5650_codecs[1].dai_name = codec_capture_dai;
}
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
......
......@@ -123,6 +123,7 @@
#define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8)
#define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4)
#define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3)
#define AFE_TDM_CON1_LRCK_INV (0x1 << 2)
#define AFE_TDM_CON1_BCK_INV (0x1 << 1)
#define AFE_TDM_CON1_EN (0x1 << 0)
......@@ -449,6 +450,7 @@ static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream,
runtime->rate * runtime->channels * 32);
val = AFE_TDM_CON1_BCK_INV |
AFE_TDM_CON1_LRCK_INV |
AFE_TDM_CON1_1_BCK_DELAY |
AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */
AFE_TDM_CON1_WLEN_32BIT |
......
......@@ -260,6 +260,10 @@ static void omap_st_on(struct omap_mcbsp *mcbsp)
if (mcbsp->pdata->enable_st_clock)
mcbsp->pdata->enable_st_clock(mcbsp->id, 1);
/* Disable Sidetone clock auto-gating for normal operation */
w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
/* Enable McBSP Sidetone */
w = MCBSP_READ(mcbsp, SSELCR);
MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
......@@ -279,6 +283,10 @@ static void omap_st_off(struct omap_mcbsp *mcbsp)
w = MCBSP_READ(mcbsp, SSELCR);
MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
/* Enable Sidetone clock auto-gating to reduce power consumption */
w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
if (mcbsp->pdata->enable_st_clock)
mcbsp->pdata->enable_st_clock(mcbsp->id, 0);
}
......
......@@ -82,6 +82,8 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
struct dma_chan *chan;
int err = 0;
memset(&config, 0x00, sizeof(config));
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* return if this is a bufferless transfer e.g.
......
......@@ -133,3 +133,4 @@ module_platform_driver(mmp_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("ALSA SoC Brownstone");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:brownstone-audio");
......@@ -207,3 +207,4 @@ module_platform_driver(mioa701_wm9713_driver);
MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mioa701-wm9713");
......@@ -248,3 +248,4 @@ module_platform_driver(mmp_pcm_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("MMP Soc Audio DMA module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mmp-pcm-audio");
......@@ -482,3 +482,4 @@ module_platform_driver(asoc_mmp_sspa_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("MMP SSPA SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mmp-sspa-dai");
......@@ -161,3 +161,4 @@ module_platform_driver(palm27x_wm9712_driver);
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:palm27x-asoc");
......@@ -833,3 +833,4 @@ module_platform_driver(asoc_ssp_driver);
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa-ssp-dai");
......@@ -287,3 +287,4 @@ module_platform_driver(pxa2xx_ac97_driver);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-ac97");
......@@ -117,3 +117,4 @@ module_platform_driver(pxa_pcm_driver);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa-pcm-audio");
......@@ -474,7 +474,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_variant *v = drvdata->variant;
int ret;
int ret = -EINVAL;
struct lpass_pcm_data *data;
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
......@@ -518,8 +518,10 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
data->wrdma_ch = v->alloc_dma_channel(drvdata,
SNDRV_PCM_STREAM_CAPTURE);
if (data->wrdma_ch < 0)
if (data->wrdma_ch < 0) {
ret = data->wrdma_ch;
goto capture_alloc_err;
}
drvdata->substream[data->wrdma_ch] = csubstream;
......
......@@ -492,9 +492,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
*/
if (!count) {
clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
parent_clk_name,
(parent_clk_name) ?
0 : CLK_IS_ROOT, req_rate);
parent_clk_name, 0, req_rate);
if (!IS_ERR(clk)) {
adg->clkout[CLKOUT] = clk;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
......@@ -506,9 +504,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
else {
for (i = 0; i < CLKOUTMAX; i++) {
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name,
(parent_clk_name) ?
0 : CLK_IS_ROOT,
parent_clk_name, 0,
req_rate);
if (!IS_ERR(clk)) {
adg->onecell.clks = adg->clkout;
......
......@@ -316,11 +316,15 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
size = ARRAY_SIZE(gen2_id_table_cmd);
}
if (!entry)
return 0xFF;
if ((!entry) || (size <= id)) {
struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
if (size <= id)
return 0xFF;
dev_err(dev, "unknown connection (%s[%d])\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
/* use non-prohibited SRS number as error */
return 0x00; /* SSI00 */
}
return entry[id];
}
......
......@@ -276,8 +276,9 @@ struct rsnd_mod {
/*
* status
*
* 0xH0000CB0
* 0xH0000CBA
*
* A 0: probe 1: remove
* B 0: init 1: quit
* C 0: start 1: stop
*
......@@ -287,19 +288,19 @@ struct rsnd_mod {
* H 0: fallback
* H 0: hw_params
*/
#define __rsnd_mod_shift_probe 0
#define __rsnd_mod_shift_remove 0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8
#define __rsnd_mod_shift_stop 8
#define __rsnd_mod_shift_probe 28 /* always called */
#define __rsnd_mod_shift_remove 28 /* always called */
#define __rsnd_mod_shift_irq 28 /* always called */
#define __rsnd_mod_shift_pcm_new 28 /* always called */
#define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove 0
#define __rsnd_mod_add_probe 1
#define __rsnd_mod_add_remove -1
#define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1
......@@ -310,7 +311,7 @@ struct rsnd_mod {
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 0
#define __rsnd_mod_call_remove 1
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
......
......@@ -572,6 +572,9 @@ int rsnd_src_probe(struct rsnd_priv *priv)
i = 0;
for_each_child_of_node(node, np) {
if (!of_device_is_available(np))
goto skip;
src = rsnd_src_get(priv, i);
snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
......@@ -595,6 +598,7 @@ int rsnd_src_probe(struct rsnd_priv *priv)
if (ret)
goto rsnd_src_probe_done;
skip:
i++;
}
......
......@@ -1023,6 +1023,11 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
if (control_hdr->size != sizeof(*control_hdr)) {
dev_err(tplg->dev, "ASoC: invalid control size\n");
return -EINVAL;
}
switch (control_hdr->ops.info) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_STROBE:
......@@ -1476,6 +1481,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
widget->dobj.type = SND_SOC_DOBJ_WIDGET;
widget->dobj.ops = tplg->ops;
widget->dobj.index = tplg->index;
kfree(template.sname);
kfree(template.name);
list_add(&widget->dobj.list, &tplg->comp->dobj_list);
return 0;
......@@ -1499,10 +1506,17 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
for (i = 0; i < count; i++) {
widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
if (widget->size != sizeof(*widget)) {
dev_err(tplg->dev, "ASoC: invalid widget size\n");
return -EINVAL;
}
ret = soc_tplg_dapm_widget_create(tplg, widget);
if (ret < 0)
if (ret < 0) {
dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
widget->name);
return ret;
}
}
return 0;
......@@ -1586,6 +1600,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
return snd_soc_register_dai(tplg->comp, dai_drv);
}
/* create the FE DAI link */
static int soc_tplg_link_create(struct soc_tplg *tplg,
struct snd_soc_tplg_pcm *pcm)
{
......@@ -1598,6 +1613,16 @@ static int soc_tplg_link_create(struct soc_tplg *tplg,
link->name = pcm->pcm_name;
link->stream_name = pcm->pcm_name;
link->id = pcm->pcm_id;
link->cpu_dai_name = pcm->dai_name;
link->codec_name = "snd-soc-dummy";
link->codec_dai_name = "snd-soc-dummy-dai";
/* enable DPCM */
link->dynamic = 1;
link->dpcm_playback = pcm->playback;
link->dpcm_capture = pcm->capture;
/* pass control to component driver for optional further init */
ret = soc_tplg_dai_link_load(tplg, link);
......@@ -1639,8 +1664,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
return 0;
pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
if (soc_tplg_check_elem_count(tplg,
sizeof(struct snd_soc_tplg_pcm), count,
hdr->payload_size, "PCM DAI")) {
......@@ -1650,7 +1673,13 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
}
/* create the FE DAIs and DAI links */
pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
for (i = 0; i < count; i++) {
if (pcm->size != sizeof(*pcm)) {
dev_err(tplg->dev, "ASoC: invalid pcm size\n");
return -EINVAL;
}
soc_tplg_pcm_create(tplg, pcm);
pcm++;
}
......@@ -1670,6 +1699,11 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
return 0;
manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
if (manifest->size != sizeof(*manifest)) {
dev_err(tplg->dev, "ASoC: invalid manifest size\n");
return -EINVAL;
}
tplg->pos += sizeof(struct snd_soc_tplg_manifest);
if (tplg->comp && tplg->ops && tplg->ops->manifest)
......@@ -1686,6 +1720,14 @@ static int soc_valid_header(struct soc_tplg *tplg,
if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
return 0;
if (hdr->size != sizeof(*hdr)) {
dev_err(tplg->dev,
"ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
hdr->type, soc_tplg_get_hdr_offset(tplg),
tplg->fw->size);
return -EINVAL;
}
/* big endian firmware objects not supported atm */
if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
dev_err(tplg->dev,
......
......@@ -10,6 +10,142 @@
#include "uniperif.h"
/*
* User frame size shall be 2, 4, 6 or 8 32-bits words length
* (i.e. 8, 16, 24 or 32 bytes)
* This constraint comes from allowed values for
* UNIPERIF_I2S_FMT_NUM_CH register
*/
#define UNIPERIF_MAX_FRAME_SZ 0x20
#define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ)
int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots,
int slot_width)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *uni = priv->dai_data.uni;
int i, frame_size, avail_slots;
if (!UNIPERIF_TYPE_IS_TDM(uni)) {
dev_err(uni->dev, "cpu dai not in tdm mode\n");
return -EINVAL;
}
/* store info in unip context */
uni->tdm_slot.slots = slots;
uni->tdm_slot.slot_width = slot_width;
/* unip is unidirectionnal */
uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask;
/* number of available timeslots */
for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) {
if ((uni->tdm_slot.mask >> i) & 0x01)
avail_slots++;
}
uni->tdm_slot.avail_slots = avail_slots;
/* frame size in bytes */
frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8;
/* check frame size is allowed */
if ((frame_size > UNIPERIF_MAX_FRAME_SZ) ||
(frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) {
dev_err(uni->dev, "frame size not allowed: %d bytes\n",
frame_size);
return -EINVAL;
}
return 0;
}
int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct uniperif *uni = rule->private;
struct snd_interval t;
t.min = uni->tdm_slot.avail_slots;
t.max = uni->tdm_slot.avail_slots;
t.openmin = 0;
t.openmax = 0;
t.integer = 0;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct uniperif *uni = rule->private;
struct snd_mask *maskp = hw_param_mask(params, rule->var);
u64 format;
switch (uni->tdm_slot.slot_width) {
case 16:
format = SNDRV_PCM_FMTBIT_S16_LE;
break;
case 32:
format = SNDRV_PCM_FMTBIT_S32_LE;
break;
default:
dev_err(uni->dev, "format not supported: %d bits\n",
uni->tdm_slot.slot_width);
return -EINVAL;
}
maskp->bits[0] &= (u_int32_t)format;
maskp->bits[1] &= (u_int32_t)(format >> 32);
/* clear remaining indexes */
memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8);
if (!maskp->bits[0] && !maskp->bits[1])
return -EINVAL;
return 0;
}
int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni,
unsigned int *word_pos)
{
int slot_width = uni->tdm_slot.slot_width / 8;
int slots_num = uni->tdm_slot.slots;
unsigned int slots_mask = uni->tdm_slot.mask;
int i, j, k;
unsigned int word16_pos[4];
/* word16_pos:
* word16_pos[0] = WORDX_LSB
* word16_pos[1] = WORDX_MSB,
* word16_pos[2] = WORDX+1_LSB
* word16_pos[3] = WORDX+1_MSB
*/
/* set unip word position */
for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) {
if ((slots_mask >> i) & 0x01) {
word16_pos[j] = i * slot_width;
if (slot_width == 4) {
word16_pos[j + 1] = word16_pos[j] + 2;
j++;
}
j++;
if (j > 3) {
word_pos[k] = word16_pos[1] |
(word16_pos[0] << 8) |
(word16_pos[3] << 16) |
(word16_pos[2] << 24);
j = 0;
k++;
}
}
}
return 0;
}
/*
* sti_uniperiph_dai_create_ctrl
* This function is used to create Ctrl associated to DAI but also pcm device.
......@@ -45,10 +181,16 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *uni = priv->dai_data.uni;
struct snd_dmaengine_dai_dma_data *dma_data;
int transfer_size;
transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES;
if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM)
/* transfer size = user frame size (in 32-bits FIFO cell) */
transfer_size = snd_soc_params_to_frame_size(params) / 32;
else
transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES;
dma_data = snd_soc_dai_get_dma_data(dai, substream);
dma_data->maxburst = transfer_size;
......
This diff is collapsed.
This diff is collapsed.
......@@ -73,55 +73,10 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
return ret;
}
static int uni_reader_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime,
struct uniperif *reader)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
struct snd_pcm_runtime *runtime = substream->runtime;
int transfer_size, trigger_limit;
int slot_width;
int count = 10;
/* The reader should be stopped */
if (reader->state != UNIPERIF_STATE_STOPPED) {
dev_err(reader->dev, "%s: invalid reader state %d", __func__,
reader->state);
return -EINVAL;
}
/* Calculate transfer size (in fifo cells and bytes) for frame count */
transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
/* Calculate number of empty cells available before asserting DREQ */
if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
else
/*
* Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
* FDMA_TRIGGER_LIMIT also controls when the state switches
* from OFF or STANDBY to AUDIO DATA.
*/
trigger_limit = transfer_size;
/* Trigger limit must be an even number */
if ((!trigger_limit % 2) ||
(trigger_limit != 1 && transfer_size % 2) ||
(trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) {
dev_err(reader->dev, "invalid trigger limit %d", trigger_limit);
return -EINVAL;
}
SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit);
switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
case SND_SOC_DAIFMT_NB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader);
break;
default:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader);
}
/* Force slot width to 32 in I2S mode */
if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK)
......@@ -173,6 +128,109 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
return -EINVAL;
}
/* Number of channels must be even */
if ((runtime->channels % 2) || (runtime->channels < 2) ||
(runtime->channels > 10)) {
dev_err(reader->dev, "%s: invalid nb of channels", __func__);
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2);
SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader);
return 0;
}
static int uni_reader_prepare_tdm(struct snd_pcm_runtime *runtime,
struct uniperif *reader)
{
int frame_size; /* user tdm frame size in bytes */
/* default unip TDM_WORD_POS_X_Y */
unsigned int word_pos[4] = {
0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A};
frame_size = sti_uniperiph_get_user_frame_size(runtime);
/* fix 16/0 format */
SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader);
SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader);
/* number of words inserted on the TDM line */
SET_UNIPERIF_I2S_FMT_NUM_CH(reader, frame_size / 4 / 2);
SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader);
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(reader);
/*
* set the timeslots allocation for words in FIFO
*
* HW bug: (LSB word < MSB word) => this config is not possible
* So if we want (LSB word < MSB) word, then it shall be
* handled by user
*/
sti_uniperiph_get_tdm_word_pos(reader, word_pos);
SET_UNIPERIF_TDM_WORD_POS(reader, 1_2, word_pos[WORD_1_2]);
SET_UNIPERIF_TDM_WORD_POS(reader, 3_4, word_pos[WORD_3_4]);
SET_UNIPERIF_TDM_WORD_POS(reader, 5_6, word_pos[WORD_5_6]);
SET_UNIPERIF_TDM_WORD_POS(reader, 7_8, word_pos[WORD_7_8]);
return 0;
}
static int uni_reader_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
struct snd_pcm_runtime *runtime = substream->runtime;
int transfer_size, trigger_limit, ret;
int count = 10;
/* The reader should be stopped */
if (reader->state != UNIPERIF_STATE_STOPPED) {
dev_err(reader->dev, "%s: invalid reader state %d", __func__,
reader->state);
return -EINVAL;
}
/* Calculate transfer size (in fifo cells and bytes) for frame count */
if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) {
/* transfer size = unip frame size (in 32 bits FIFO cell) */
transfer_size =
sti_uniperiph_get_user_frame_size(runtime) / 4;
} else {
transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
}
/* Calculate number of empty cells available before asserting DREQ */
if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
else
/*
* Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
* FDMA_TRIGGER_LIMIT also controls when the state switches
* from OFF or STANDBY to AUDIO DATA.
*/
trigger_limit = transfer_size;
/* Trigger limit must be an even number */
if ((!trigger_limit % 2) ||
(trigger_limit != 1 && transfer_size % 2) ||
(trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) {
dev_err(reader->dev, "invalid trigger limit %d", trigger_limit);
return -EINVAL;
}
SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit);
if (UNIPERIF_TYPE_IS_TDM(reader))
ret = uni_reader_prepare_tdm(runtime, reader);
else
ret = uni_reader_prepare_pcm(runtime, reader);
if (ret)
return ret;
switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
......@@ -191,21 +249,26 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
return -EINVAL;
}
SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader);
/* Data clocking (changing) on the rising edge */
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader);
/* Number of channels must be even */
if ((runtime->channels % 2) || (runtime->channels < 2) ||
(runtime->channels > 10)) {
dev_err(reader->dev, "%s: invalid nb of channels", __func__);
return -EINVAL;
/* Data clocking (changing) on the rising/falling edge */
switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader);
break;
case SND_SOC_DAIFMT_NB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader);
break;
case SND_SOC_DAIFMT_IB_NF:
SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader);
break;
case SND_SOC_DAIFMT_IB_IF:
SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader);
SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader);
break;
}
SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2);
/* Clear any pending interrupts */
SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader));
......@@ -293,6 +356,32 @@ static int uni_reader_trigger(struct snd_pcm_substream *substream,
}
}
static int uni_reader_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni;
int ret;
if (!UNIPERIF_TYPE_IS_TDM(reader))
return 0;
/* refine hw constraint in tdm mode */
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
sti_uniperiph_fix_tdm_chan,
reader, SNDRV_PCM_HW_PARAM_CHANNELS,
-1);
if (ret < 0)
return ret;
return snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
sti_uniperiph_fix_tdm_format,
reader, SNDRV_PCM_HW_PARAM_FORMAT,
-1);
}
static void uni_reader_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
......@@ -310,6 +399,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev,
{
struct uniperif_info *info;
struct device_node *node = pdev->dev.of_node;
const char *mode;
/* Allocate memory for the info structure */
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
......@@ -322,6 +412,17 @@ static int uni_reader_parse_dt(struct platform_device *pdev,
return -EINVAL;
}
/* Read the device mode property */
if (of_property_read_string(node, "st,mode", &mode)) {
dev_err(&pdev->dev, "uniperipheral mode not defined");
return -EINVAL;
}
if (strcasecmp(mode, "tdm") == 0)
info->type = SND_ST_UNIPERIF_TYPE_TDM;
else
info->type = SND_ST_UNIPERIF_TYPE_PCM;
/* Save the info structure */
reader->info = info;
......@@ -329,11 +430,13 @@ static int uni_reader_parse_dt(struct platform_device *pdev,
}
static const struct snd_soc_dai_ops uni_reader_dai_ops = {
.startup = uni_reader_startup,
.shutdown = uni_reader_shutdown,
.prepare = uni_reader_prepare,
.trigger = uni_reader_trigger,
.hw_params = sti_uniperiph_dai_hw_params,
.set_fmt = sti_uniperiph_dai_set_fmt,
.set_tdm_slot = sti_uniperiph_set_tdm_slot
};
int uni_reader_init(struct platform_device *pdev,
......@@ -343,7 +446,6 @@ int uni_reader_init(struct platform_device *pdev,
reader->dev = &pdev->dev;
reader->state = UNIPERIF_STATE_STOPPED;
reader->hw = &uni_reader_pcm_hw;
reader->dai_ops = &uni_reader_dai_ops;
ret = uni_reader_parse_dt(pdev, reader);
......@@ -352,6 +454,11 @@ int uni_reader_init(struct platform_device *pdev,
return ret;
}
if (UNIPERIF_TYPE_IS_TDM(reader))
reader->hw = &uni_tdm_hw;
else
reader->hw = &uni_reader_pcm_hw;
ret = devm_request_irq(&pdev->dev, reader->irq,
uni_reader_irq_handler, IRQF_SHARED,
dev_name(&pdev->dev), reader);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment