diff options
46 files changed, 1212 insertions, 702 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml b/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml new file mode 100644 index 000000000000..d12774b42a11 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,mxs-audio-sgtl5000.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,mxs-audio-sgtl5000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale MXS audio complex with SGTL5000 codec + +maintainers: + - Frank Li <Frank.Li@nxp.com> + +properties: + compatible: + items: + - enum: + - bluegiga,apx4devkit-sgtl5000 + - denx,m28evk-sgtl5000 + - fsl,imx28-evk-sgtl5000 + - fsl,imx28-mbmx28lc-sgtl5000 + - fsl,imx28-tx28-sgtl5000 + - const: fsl,mxs-audio-sgtl5000 + + model: + $ref: /schemas/types.yaml#/definitions/string + description: The user-visible name of this sound complex + + saif-controllers: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: The phandle list of the MXS SAIF controller + + audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the SGTL5000 audio codec + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk + +required: + - compatible + - saif-controllers + - audio-codec + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "fsl,imx28-evk-sgtl5000", "fsl,mxs-audio-sgtl5000"; + model = "imx28-evk-sgtl5000"; + saif-controllers = <&saif0 &saif1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + }; diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt deleted file mode 100644 index 4eb980bd0287..000000000000 --- a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt +++ /dev/null @@ -1,42 +0,0 @@ -* Freescale MXS audio complex with SGTL5000 codec - -Required properties: -- compatible : "fsl,mxs-audio-sgtl5000" -- model : The user-visible name of this sound complex -- saif-controllers : The phandle list of the MXS SAIF controller -- audio-codec : The phandle of the SGTL5000 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, SGTL5000 - pins, and the jacks on the board: - - Power supplies: - * Mic Bias - - SGTL5000 pins: - * MIC_IN - * LINE_IN - * HP_OUT - * LINE_OUT - - Board connectors: - * Mic Jack - * Line In Jack - * Headphone Jack - * Line Out Jack - * Ext Spk - -Example: - -sound { - compatible = "fsl,imx28-evk-sgtl5000", - "fsl,mxs-audio-sgtl5000"; - model = "imx28-evk-sgtl5000"; - saif-controllers = <&saif0 &saif1>; - audio-codec = <&sgtl5000>; - audio-routing = - "MIC_IN", "Mic Jack", - "Mic Jack", "Mic Bias", - "Headphone Jack", "HP_OUT"; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml index c69291f4d575..85283f94465d 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd939x.yaml @@ -45,6 +45,9 @@ properties: purpose of handling altmode muxing and orientation switching to detect and enable Audio Accessory Mode. + vdd-px-supply: + description: A reference to the 1.2V PX supply + required: - compatible diff --git a/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml b/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml index 5acb05cdfefd..819ca06203b1 100644 --- a/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml +++ b/Documentation/devicetree/bindings/sound/richtek,rt9123.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/sound/richtek,rt9123.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Richtek RT9123 Audio Amplifier +title: Richtek RT9123/RTQ9124 Audio Amplifier maintainers: - ChiYuan Huang <cy_huang@richtek.com> @@ -15,6 +15,12 @@ description: support various formats, including I2S, left-justified, right-justified, and TDM formats. + RTQ9124 is an ultra-low output noise, digital input, mono-channel Class-D + power amplifier that supports a 2.1MHz switching frequency. It integrates + both DC and AC load diagnostics, as well as real-time load monitoring to + assess speaker condition. The device operates from 4.5V to 18V and delivers + up to 30W output power. + allOf: - $ref: dai-common.yaml# @@ -22,6 +28,7 @@ properties: compatible: enum: - richtek,rt9123 + - richtek,rtq9124 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml index 74f7d02b424b..0b013a34e2c1 100644 --- a/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas57xx.yaml @@ -18,6 +18,7 @@ properties: - ti,tas5719 - ti,tas5721 - ti,tas5733 + - ti,tas5753 reg: maxItems: 1 @@ -98,6 +99,7 @@ allOf: contains: enum: - ti,tas5721 + - ti,tas5753 then: properties: HPVDD-supply: false diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 61534ac0edd1..2caa807c6249 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -206,7 +206,6 @@ struct snd_soc_component_driver { struct snd_soc_component { const char *name; - int id; const char *name_prefix; struct device *dev; struct snd_soc_card *card; diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 0b2aa33cc426..2591b1a1c5e0 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -137,26 +137,26 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id chip->name = "acp_asoc_renoir"; chip->rsrc = &rn_rsrc; chip->acp_hw_ops_init = acp31_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp_machines; + chip->machines = snd_soc_acpi_amd_acp_machines; break; case 0x6f: chip->name = "acp_asoc_rembrandt"; chip->rsrc = &rmb_rsrc; chip->acp_hw_ops_init = acp6x_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_rmb_acp_machines; + chip->machines = snd_soc_acpi_amd_rmb_acp_machines; break; case 0x63: chip->name = "acp_asoc_acp63"; chip->rsrc = &acp63_rsrc; chip->acp_hw_ops_init = acp63_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp63_acp_machines; + chip->machines = snd_soc_acpi_amd_acp63_acp_machines; break; case 0x70: case 0x71: chip->name = "acp_asoc_acp70"; chip->rsrc = &acp70_rsrc; chip->acp_hw_ops_init = acp70_hw_ops_init; - chip->machines = &snd_soc_acpi_amd_acp70_acp_machines; + chip->machines = snd_soc_acpi_amd_acp70_acp_machines; break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); diff --git a/sound/soc/amd/acp/amd-acpi-mach.c b/sound/soc/amd/acp/amd-acpi-mach.c index d95047d2ee94..27da2a862f1c 100644 --- a/sound/soc/amd/acp/amd-acpi-mach.c +++ b/sound/soc/amd/acp/amd-acpi-mach.c @@ -8,12 +8,12 @@ #include <sound/soc-acpi.h> -struct snd_soc_acpi_codecs amp_rt1019 = { +static struct snd_soc_acpi_codecs amp_rt1019 = { .num_codecs = 1, .codecs = {"10EC1019"} }; -struct snd_soc_acpi_codecs amp_max = { +static struct snd_soc_acpi_codecs amp_max = { .num_codecs = 1, .codecs = {"MX98360A"} }; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 863e74fcee43..cb8d97122f95 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -243,10 +243,10 @@ extern struct acp_resource rmb_rsrc; extern struct acp_resource acp63_rsrc; extern struct acp_resource acp70_rsrc; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[]; extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 126f897312d4..6d7e4725d89c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1320_SDW imply SND_SOC_RT9120 imply SND_SOC_RT9123 + imply SND_SOC_RTQ9124 imply SND_SOC_RTQ9128 imply SND_SOC_SDW_MOCKUP imply SND_SOC_SGTL5000 @@ -263,9 +264,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS2764 imply SND_SOC_TAS2770 imply SND_SOC_TAS2780 - imply SND_SOC_TAS2781_COMLIB - imply SND_SOC_TAS2781_COMLIB_I2C - imply SND_SOC_TAS2781_FMWLIB imply SND_SOC_TAS2781_I2C imply SND_SOC_TAS5086 imply SND_SOC_TAS571X @@ -1858,6 +1856,14 @@ config SND_SOC_RT9123P Enable support for the HW control mode of Richtek RT9123P 3.2W mono Class-D audio amplifier. +config SND_SOC_RTQ9124 + tristate "Richtek RTQ9124 Mono Class-D Amplifier" + depends on I2C + select REGMAP + help + Enable support for Richtek RTQ9124 1x30W digital input automotive + audio amplifier with current sense and real-time load diagnostics. + config SND_SOC_RTQ9128 tristate "Richtek RTQ9128 45W Digital Input Amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6d7aa109ede7..a68c3d192a1b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -275,6 +275,7 @@ snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o snd-soc-rt9120-y := rt9120.o snd-soc-rt9123-y := rt9123.o snd-soc-rt9123p-y := rt9123p.o +snd-soc-rtq9124-y := rtq9124.o snd-soc-rtq9128-y := rtq9128.o snd-soc-sdw-mockup-y := sdw-mockup.o snd-soc-sgtl5000-y := sgtl5000.o @@ -695,6 +696,7 @@ obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o +obj-$(CONFIG_SND_SOC_RTQ9124) += snd-soc-rtq9124.o obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o @@ -853,4 +855,4 @@ obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO) += snd-soc-lpass-rx-macro.o obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO) += snd-soc-lpass-tx-macro.o # Mux -obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o
\ No newline at end of file +obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1139a2754ca3..e05f0bf91fa5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -25,7 +25,6 @@ #include <sound/pcm_drm_eld.h> #include <sound/hda_chmap.h> #include "../../hda/local.h" -#include "hdac_hdmi.h" #define NAME_SIZE 32 @@ -1431,122 +1430,6 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev) } -static int hdac_hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port; - struct hdac_hdmi_eld *eld; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = 0; - - pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); - if (!pcm) { - dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, - kcontrol->id.device); - return 0; - } - - if (list_empty(&pcm->port_list)) { - dev_dbg(component->dev, "%s: empty port list, device %d\n", - __func__, kcontrol->id.device); - return 0; - } - - mutex_lock(&hdmi->pin_mutex); - - list_for_each_entry(port, &pcm->port_list, head) { - eld = &port->eld; - - if (eld->eld_valid) { - uinfo->count = eld->eld_size; - break; - } - } - - mutex_unlock(&hdmi->pin_mutex); - - return 0; -} - -static int hdac_hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port; - struct hdac_hdmi_eld *eld; - - memset(ucontrol->value.bytes.data, 0, sizeof(ucontrol->value.bytes.data)); - - pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); - if (!pcm) { - dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, - kcontrol->id.device); - return 0; - } - - if (list_empty(&pcm->port_list)) { - dev_dbg(component->dev, "%s: empty port list, device %d\n", - __func__, kcontrol->id.device); - return 0; - } - - mutex_lock(&hdmi->pin_mutex); - - list_for_each_entry(port, &pcm->port_list, head) { - eld = &port->eld; - - if (!eld->eld_valid) - continue; - - if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || - eld->eld_size > ELD_MAX_SIZE) { - mutex_unlock(&hdmi->pin_mutex); - - dev_err(component->dev, "%s: buffer too small, device %d eld_size %d\n", - __func__, kcontrol->id.device, eld->eld_size); - snd_BUG(); - return -EINVAL; - } - - memcpy(ucontrol->value.bytes.data, eld->eld_buffer, - eld->eld_size); - break; - } - - mutex_unlock(&hdmi->pin_mutex); - - return 0; -} - -static int hdac_hdmi_create_eld_ctl(struct snd_soc_component *component, struct hdac_hdmi_pcm *pcm) -{ - struct snd_kcontrol *kctl; - struct snd_kcontrol_new hdmi_eld_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdac_hdmi_eld_ctl_info, - .get = hdac_hdmi_eld_ctl_get, - .device = pcm->pcm_id, - }; - - /* add ELD ctl with the device number corresponding to the PCM stream */ - kctl = snd_ctl_new1(&hdmi_eld_ctl, component); - if (!kctl) - return -ENOMEM; - - pcm->eld_ctl = kctl; - - return snd_ctl_add(component->card->snd_card, kctl); -} - static const struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, @@ -1754,186 +1637,6 @@ static struct drm_audio_component_audio_ops aops = { .pin_eld_notify = hdac_hdmi_eld_notify_cb, }; -static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, - int device) -{ - struct snd_soc_pcm_runtime *rtd; - - for_each_card_rtds(card, rtd) { - if (rtd->pcm && (rtd->pcm->device == device)) - return rtd->pcm; - } - - return NULL; -} - -/* create jack pin kcontrols */ -static int create_fill_jack_kcontrols(struct snd_soc_card *card, - struct hdac_device *hdev) -{ - struct hdac_hdmi_pin *pin; - struct snd_kcontrol_new *kc; - char *name; - int i = 0, j; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct snd_soc_component *component = hdmi->component; - - kc = devm_kcalloc(component->dev, hdmi->num_ports, - sizeof(*kc), GFP_KERNEL); - - if (!kc) - return -ENOMEM; - - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) { - name = devm_kasprintf(component->dev, GFP_KERNEL, - "hif%d-%d Jack", - pin->nid, pin->ports[j].id); - if (!name) - return -ENOMEM; - - kc[i].name = devm_kasprintf(component->dev, GFP_KERNEL, - "%s Switch", name); - if (!kc[i].name) - return -ENOMEM; - - kc[i].private_value = (unsigned long)name; - kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc[i].access = 0; - kc[i].info = snd_soc_dapm_info_pin_switch; - kc[i].put = snd_soc_dapm_put_pin_switch; - kc[i].get = snd_soc_dapm_get_pin_switch; - i++; - } - } - - return snd_soc_add_card_controls(card, kc, i); -} - -int hdac_hdmi_jack_port_init(struct snd_soc_component *component, - struct snd_soc_dapm_context *dapm) -{ - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = hdmi->hdev; - struct hdac_hdmi_pin *pin; - struct snd_soc_dapm_widget *widgets; - struct snd_soc_dapm_route *route; - char w_name[NAME_SIZE]; - int i = 0, j, ret; - - widgets = devm_kcalloc(dapm->dev, hdmi->num_ports, - sizeof(*widgets), GFP_KERNEL); - - if (!widgets) - return -ENOMEM; - - route = devm_kcalloc(dapm->dev, hdmi->num_ports, - sizeof(*route), GFP_KERNEL); - if (!route) - return -ENOMEM; - - /* create Jack DAPM widget */ - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) { - snprintf(w_name, sizeof(w_name), "hif%d-%d Jack", - pin->nid, pin->ports[j].id); - - ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_spk, NULL, - w_name, NULL, NULL, 0, NULL, 0); - if (ret < 0) - return ret; - - pin->ports[j].jack_pin = widgets[i].name; - pin->ports[j].dapm = dapm; - - /* add to route from Jack widget to output */ - hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin, - NULL, pin->ports[j].output_pin, NULL); - - i++; - } - } - - /* Add Route from Jack widget to the output widget */ - ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports); - if (ret < 0) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports); - if (ret < 0) - return ret; - - ret = snd_soc_dapm_new_widgets(dapm->card); - if (ret < 0) - return ret; - - /* Add Jack Pin switch Kcontrol */ - ret = create_fill_jack_kcontrols(dapm->card, hdev); - - if (ret < 0) - return ret; - - /* default set the Jack Pin switch to OFF */ - list_for_each_entry(pin, &hdmi->pin_list, head) { - for (j = 0; j < pin->num_ports; j++) - snd_soc_dapm_disable_pin(pin->ports[j].dapm, - pin->ports[j].jack_pin); - } - - return 0; -} -EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init); - -int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, - struct snd_soc_jack *jack) -{ - struct snd_soc_component *component = dai->component; - struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = hdmi->hdev; - struct hdac_hdmi_pcm *pcm; - struct snd_pcm *snd_pcm; - int err; - - /* - * this is a new PCM device, create new pcm and - * add to the pcm list - */ - pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - pcm->pcm_id = device; - pcm->cvt = hdmi->dai_map[dai->id].cvt; - pcm->jack_event = 0; - pcm->jack = jack; - mutex_init(&pcm->lock); - INIT_LIST_HEAD(&pcm->port_list); - snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); - if (snd_pcm) { - err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); - if (err < 0) { - dev_err(&hdev->dev, - "chmap control add failed with err: %d for pcm: %d\n", - err, device); - return err; - } - } - - /* add control for ELD Bytes */ - err = hdac_hdmi_create_eld_ctl(component, pcm); - if (err < 0) { - dev_err(&hdev->dev, - "eld control add failed with err: %d for pcm: %d\n", - err, device); - return err; - } - - list_add_tail(&pcm->head, &hdmi->pcm_list); - - return 0; -} -EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); - static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev, struct hdac_hdmi_priv *hdmi, bool detect_pin_caps) { diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h deleted file mode 100644 index 493fa3b4ef75..000000000000 --- a/sound/soc/codecs/hdac_hdmi.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __HDAC_HDMI_H__ -#define __HDAC_HDMI_H__ - -int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, - struct snd_soc_jack *jack); - -int hdac_hdmi_jack_port_init(struct snd_soc_component *component, - struct snd_soc_dapm_context *dapm); -#endif /* __HDAC_HDMI_H__ */ diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 45a6b83808b2..238dbdb46c18 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -619,7 +619,6 @@ static struct interp_sample_rate sr_val_tbl[] = { }; enum { - RX_MACRO_AIF_INVALID = 0, RX_MACRO_AIF1_PB, RX_MACRO_AIF2_PB, RX_MACRO_AIF3_PB, diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 27bae58f4072..40d79bee4584 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -208,7 +208,6 @@ #define MCLK_FREQ 19200000 enum { - TX_MACRO_AIF_INVALID = 0, TX_MACRO_AIF1_CAP, TX_MACRO_AIF2_CAP, TX_MACRO_AIF3_CAP, diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 74ada6e77526..a49551f3fb29 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -165,7 +165,6 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); enum { - VA_MACRO_AIF_INVALID = 0, VA_MACRO_AIF1_CAP, VA_MACRO_AIF2_CAP, VA_MACRO_AIF3_CAP, diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index c1fb71cfb5d0..da6adb3de21d 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -369,7 +369,6 @@ static struct interp_sample_rate int_mix_sample_rate_val[] = { }; enum { - WSA_MACRO_AIF_INVALID = 0, WSA_MACRO_AIF1_PB, WSA_MACRO_AIF_MIX1_PB, WSA_MACRO_AIF_VI, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 21a18012b4c0..f50e771db24b 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -193,7 +193,7 @@ static bool rt5640_volatile_register(struct device *dev, unsigned int reg) case RT5640_PRIV_DATA: case RT5640_PGM_REG_ARR1: case RT5640_PGM_REG_ARR3: - case RT5640_DUMMY2: + case RT5640_GCTL2: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: case RT5640_VENDOR_ID2: @@ -325,8 +325,8 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg) case RT5640_HP_CALIB2: case RT5640_SV_ZCD1: case RT5640_SV_ZCD2: - case RT5640_DUMMY1: - case RT5640_DUMMY2: + case RT5640_GCTL1: + case RT5640_GCTL2: case RT5640_DUMMY3: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: @@ -423,7 +423,7 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), - SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1, + SOC_DOUBLE("Mono ADC Capture Switch", RT5640_GCTL1, RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1), SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, @@ -1969,7 +1969,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); - snd_soc_component_update_bits(component, RT5640_DUMMY1, + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x1, 0x1); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); @@ -1979,7 +1979,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, case SND_SOC_BIAS_OFF: snd_soc_component_write(component, RT5640_DEPOP_M1, 0x0004); snd_soc_component_write(component, RT5640_DEPOP_M2, 0x1100); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x1, 0); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x1, 0); snd_soc_component_write(component, RT5640_PWR_DIG1, 0x0000); snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000); snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000); @@ -2328,12 +2328,12 @@ static void rt5640_jack_work(struct work_struct *work) jack_type |= SND_JACK_MICROPHONE; /* headphone jack */ - val = snd_soc_component_read(component, RT5640_DUMMY2); + val = snd_soc_component_read(component, RT5640_GCTL2); hda_hp_plugged = !(val & (0x1 << 11)); dev_dbg(component->dev, "headphone jack status %d\n", hda_hp_plugged); - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, (0x1 << 10), !hda_hp_plugged << 10); if (hda_hp_plugged) @@ -2504,7 +2504,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41); + snd_soc_component_write(component, RT5640_GCTL1, 0x3f41); rt5640_set_ovcd_params(component); @@ -2519,7 +2519,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | RT5640_JD2_EN); } else { @@ -2527,7 +2527,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR | RT5640_JD_P_INV); else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) - snd_soc_component_update_bits(component, RT5640_DUMMY2, + snd_soc_component_update_bits(component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | RT5640_JD2_P_INV | @@ -2596,7 +2596,7 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); /* Select JD2 for Headphone */ - snd_soc_component_update_bits(component, RT5640_DUMMY2, 0x1100, 0x1100); + snd_soc_component_update_bits(component, RT5640_GCTL2, 0x1100, 0x1100); /* Selecting GPIO01 as an interrupt */ snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, @@ -2606,7 +2606,7 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x400, 0x0); snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG, @@ -2668,7 +2668,7 @@ static int rt5640_probe(struct snd_soc_component *component) snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x0301, 0x0301); + snd_soc_component_update_bits(component, RT5640_GCTL1, 0x0301, 0x0301); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); snd_soc_component_update_bits(component, RT5640_DSP_PATH2, 0xfc00, 0x0c00); @@ -2719,7 +2719,7 @@ static int rt5640_probe(struct snd_soc_component *component) RT5640_IN_DF2, RT5640_IN_DF2); if (device_property_read_bool(component->dev, "realtek,lout-differential")) - snd_soc_component_update_bits(component, RT5640_DUMMY1, + snd_soc_component_update_bits(component, RT5640_GCTL1, RT5640_EN_LOUT_DF, RT5640_EN_LOUT_DF); if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin", @@ -2829,12 +2829,12 @@ static int rt5640_resume(struct snd_soc_component *component) if (rt5640->jack) { if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { snd_soc_component_update_bits(component, - RT5640_DUMMY2, 0x1100, 0x1100); + RT5640_GCTL2, 0x1100, 0x1100); } else { if (rt5640->jd_inverted) { if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) snd_soc_component_update_bits( - component, RT5640_DUMMY2, + component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK, RT5640_IRQ_JD2_NOR | @@ -2843,7 +2843,7 @@ static int rt5640_resume(struct snd_soc_component *component) } else { if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) snd_soc_component_update_bits( - component, RT5640_DUMMY2, + component, RT5640_GCTL2, RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK | RT5640_JD2_MASK, @@ -3014,6 +3014,11 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { + usleep_range(60000, 100000); + regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); + } + + if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5640/39\n", val); return -ENODEV; @@ -3026,7 +3031,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); - regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, + regmap_update_bits(rt5640->regmap, RT5640_GCTL1, RT5640_MCLK_DET, RT5640_MCLK_DET); rt5640->hp_mute = true; diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 94b9a502f7f9..8a12cee76bdc 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -139,8 +139,8 @@ #define RT5640_SV_ZCD1 0xd9 #define RT5640_SV_ZCD2 0xda /* Dummy Register */ -#define RT5640_DUMMY1 0xfa -#define RT5640_DUMMY2 0xfb +#define RT5640_GCTL1 0xfa +#define RT5640_GCTL2 0xfb #define RT5640_DUMMY3 0xfc @@ -1986,7 +1986,7 @@ #define RT5640_M_MONO_ADC_R_SFT 12 #define RT5640_MCLK_DET (0x1 << 11) -/* General Control 1 (0xfb) */ +/* General Control 2 (0xfb) */ #define RT5640_IRQ_JD2_MASK (0x1 << 12) #define RT5640_IRQ_JD2_SFT 12 #define RT5640_IRQ_JD2_BP (0x0 << 12) diff --git a/sound/soc/codecs/rtq9124.c b/sound/soc/codecs/rtq9124.c new file mode 100644 index 000000000000..186904b31434 --- /dev/null +++ b/sound/soc/codecs/rtq9124.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rtq9124.c -- RTQ9124 ALSA SoC Codec driver +// +// Author: ChiYuan Huang <cy_huang@richtek.com> + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/byteorder/generic.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#define RTQ9124_REG_SDI_SEL 0x00 +#define RTQ9124_REG_SDO_SEL 0x01 +#define RTQ9124_REG_I2S_OPT 0x02 +#define RTQ9124_REG_AMP_OPT 0x03 +#define RTQ9124_REG_STATE_CTRL 0x04 +#define RTQ9124_REG_PWM_PHASE 0x05 +#define RTQ9124_REG_SIL_CTRL 0x06 +#define RTQ9124_REG_PWM_SS_OPT 0x07 +#define RTQ9124_REG_ERR_INT_0 0x10 +#define RTQ9124_REG_ERR_MASK6 0x26 +#define RTQ9124_REG_TDM_TX_CH0 0x32 +#define RTQ9124_REG_TDM_RX_CH0 0x34 +#define RTQ9124_REG_VOL_OPT 0x38 +#define RTQ9124_REG_DCR_TH 0x4B +#define RTQ9124_REG_ERR_TH 0x4C +#define RTQ9124_REG_PROT_EN 0x5B +#define RTQ9124_REG_PRJ_CODE 0xF9 + +#define RTQ9124_MASK_CS_DATA_INV BIT(9) +#define RTQ9124_MASK_VDDIO_SDO_SEL BIT(8) +#define RTQ9124_MASK_AUD_BITS GENMASK(5, 4) +#define RTQ9124_MASK_AUD_FMT GENMASK(3, 0) +#define RTQ9124_MASK_CH_STATE GENMASK(1, 0) +#define RTQ9124_MASK_SF_RESET BIT(15) + +#define RTQ9124_FIXED_VENID 0x9124 + +struct rtq9124_priv { + struct gpio_desc *enable; + unsigned int dai_fmt; + int tdm_slots; + int tdm_slot_width; +}; + +static int rtq9124_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int i, chan_state; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Change state to normal */ + chan_state = 0; + break; + case SND_SOC_DAPM_POST_PMD: + /* Change state to HiZ */ + chan_state = 1; + break; + default: + return -EINVAL; + } + + /* Before amp turn on, clear old events first */ + for (i = 0; !chan_state && i < 8; i++) + snd_soc_component_write(comp, RTQ9124_REG_ERR_INT_0 + i, 0xffff); + + snd_soc_component_write_field(comp, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_CH_STATE, + chan_state); + + return 0; +} + +static const struct snd_soc_dapm_widget rtq9124_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rtq9124_enable_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route rtq9124_dapm_routes[] = { + { "Amp Drv", NULL, "HiFi Playback" }, + { "SPK", NULL, "Amp Drv" }, +}; + +static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0); +static const DECLARE_TLV_DB_RANGE(ana_tlv, + 0, 3, TLV_DB_SCALE_ITEM(-600, 600, 0), + 4, 6, TLV_DB_SCALE_ITEM(1400, 200, 0)); +static const char * const i2sch_text[] = { "(L+R)/2", "LCH", "RCH", "(L+R)/2" }; +static const struct soc_enum rtq9124_i2sch_select_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_SDI_SEL, 0, ARRAY_SIZE(i2sch_text), i2sch_text); +static const char * const sdo_vsel_text[] = { "1.8V", "3.3V" }; +static const struct soc_enum rtq9124_sdo_vselect_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_SDO_SEL, 8, ARRAY_SIZE(sdo_vsel_text), sdo_vsel_text); +static const char * const pwmfreq_text[] = { "8*fs", "10*fs", "40*fs", "44*fs", "48*fs" }; +static const struct soc_enum rtq9124_pwm_freq_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_AMP_OPT, 4, ARRAY_SIZE(pwmfreq_text), pwmfreq_text); +static const char * const out_angle_text[] = { "0", "45", "90", "135", "180", "225", "270", "315" }; +static const struct soc_enum rtq9124_out_angle_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_PWM_PHASE, 0, ARRAY_SIZE(out_angle_text), out_angle_text); +static const char * const sdo_select_text[] = { + "None", "I2S DataI", "Interface", "DSP", "DF", "ISense", "ACLoad Cos", "ACLoad Sin", + "DCR", +}; +static const struct soc_enum rtq9124_sdo_select_enum = + SOC_ENUM_DOUBLE(RTQ9124_REG_SDO_SEL, 4, 0, ARRAY_SIZE(sdo_select_text), sdo_select_text); +static const char * const ulqm_dcvt_text[] = { "Disable", "DC", "VT", "DC+VT" }; +static const struct soc_enum rtq9124_ulqm_dcvt_select_enum = + SOC_ENUM_SINGLE(RTQ9124_REG_STATE_CTRL, 10, ARRAY_SIZE(ulqm_dcvt_text), ulqm_dcvt_text); + +static const struct snd_kcontrol_new rtq9124_controls[] = { + SOC_SINGLE_TLV("Master Volume", RTQ9124_REG_VOL_OPT, 2, 511, 1, dig_tlv), + SOC_SINGLE_TLV("Speaker Volume", RTQ9124_REG_AMP_OPT, 0, 6, 0, ana_tlv), + SOC_ENUM("I2S CH Select", rtq9124_i2sch_select_enum), + SOC_ENUM("SDO VDDIO Select", rtq9124_sdo_vselect_enum), + SOC_ENUM("PWM Frequency Select", rtq9124_pwm_freq_enum), + SOC_ENUM("PWM Output Phase Select", rtq9124_out_angle_enum), + SOC_ENUM("SDO Select", rtq9124_sdo_select_enum), + SOC_ENUM("ULQM DCVT Select", rtq9124_ulqm_dcvt_select_enum), + SOC_SINGLE("Silence Detect Enable Switch", RTQ9124_REG_SIL_CTRL, 7, 1, 0), + SOC_SINGLE("Spread Spectrum Enable Switch", RTQ9124_REG_PWM_SS_OPT, 7, 1, 0), +}; + +static int rtq9124_comp_probe(struct snd_soc_component *comp) +{ + /* CS Data INV */ + snd_soc_component_write_field(comp, RTQ9124_REG_SDO_SEL, RTQ9124_MASK_CS_DATA_INV, 1); + + /* RTLD */ + snd_soc_component_write(comp, RTQ9124_REG_DCR_TH, 0x5e30); + snd_soc_component_write(comp, RTQ9124_REG_ERR_TH, 0x3ff); + snd_soc_component_write(comp, RTQ9124_REG_PROT_EN, 0x3fc); + snd_soc_component_write(comp, RTQ9124_REG_ERR_MASK6, 0); + + return 0; +} + +static const struct snd_soc_component_driver rtq9124_comp_driver = { + .probe = rtq9124_comp_probe, + .controls = rtq9124_controls, + .num_controls = ARRAY_SIZE(rtq9124_controls), + .dapm_widgets = rtq9124_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rtq9124_dapm_widgets), + .dapm_routes = rtq9124_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rtq9124_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int rtq9124_dai_set_format(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + + rtq9124->dai_fmt = fmt; + return 0; +} + +static int rtq9124_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *comp = dai->component; + struct device *dev = dai->dev; + unsigned int byte_loc, i; + + dev_dbg(dev, "(slots, slot_width) = (%d, %d), (txmask, rxmask) = 0x%x, 0x%x\n", slots, + slot_width, tx_mask, rx_mask); + + if (slots <= 0 || slots > 16 || slot_width <= 0 || slots % 2 || slot_width % 8) { + dev_err(dev, "Invalid slot parameter (%d, %d)\n", slots, slot_width); + return -EINVAL; + } + + if (tx_mask && (hweight_long(tx_mask) > 2 || fls(tx_mask) > slots)) { + dev_err(dev, "Invalid tx_mask 0x%08x, slots = %d\n", tx_mask, slots); + return -EINVAL; + } + + if (!rx_mask || hweight_long(rx_mask) > 1 || fls(rx_mask) > slots) { + dev_err(dev, "Invalid rx_mask 0x%08x, slots = %d\n", rx_mask, slots); + return -EINVAL; + } + + /* Configure tx channel data location */ + for (i = 0; tx_mask; i++, tx_mask ^= BIT(ffs(tx_mask) - 1)) { + byte_loc = (ffs(tx_mask) - 1) * slot_width / 8; + snd_soc_component_write(comp, RTQ9124_REG_TDM_TX_CH0 + i, byte_loc); + } + + /* Configure rx channel data location */ + byte_loc = (ffs(rx_mask) - 1) * slot_width / 8; + snd_soc_component_write(comp, RTQ9124_REG_TDM_RX_CH0, byte_loc); + + rtq9124->tdm_slots = slots; + rtq9124->tdm_slot_width = slot_width; + + return 0; +} + +static int rtq9124_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *param, struct snd_soc_dai *dai) +{ + struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai); + struct snd_soc_component *comp = dai->component; + unsigned int fmtval, width, slot_width, bitrate; + struct device *dev = dai->dev; + unsigned int audfmt, audbit; + + fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, rtq9124->dai_fmt); + if (rtq9124->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && + fmtval != SND_SOC_DAIFMT_DSP_B) { + dev_err(dev, "TDM only can support DSP_A or DSP_B format\n"); + return -EINVAL; + } + + switch (fmtval) { + case SND_SOC_DAIFMT_I2S: + audfmt = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + audfmt = 1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + audfmt = 2; + break; + case SND_SOC_DAIFMT_DSP_B: + audfmt = rtq9124->tdm_slots ? 7 : 3; + break; + case SND_SOC_DAIFMT_DSP_A: + audfmt = rtq9124->tdm_slots ? 15 : 11; + break; + default: + dev_err(dev, "Unsupported format %d\n", fmtval); + return -EINVAL; + } + + switch (width = params_width(param)) { + case 16: + audbit = 0; + break; + case 20: + audbit = 1; + break; + case 24: + case 32: + audbit = 3; + break; + default: + dev_err(dev, "Unsupported width %d\n", width); + return -EINVAL; + } + + if (rtq9124->tdm_slots) { + slot_width = params_physical_width(param); + if (slot_width > rtq9124->tdm_slot_width) { + dev_err(dev, "Slot width is larger than TDM slot width\n"); + return -EINVAL; + } + + bitrate = rtq9124->tdm_slots * rtq9124->tdm_slot_width * params_rate(param); + if (bitrate > 24576000) { + dev_err(dev, "Bitrate exceed the internal PLL 24.576MHz (%d)\n", bitrate); + return -EINVAL; + } + } + + snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_FMT, audfmt); + snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_BITS, audbit); + + return 0; +} + +static const struct snd_soc_dai_ops rtq9124_dai_ops = { + .set_fmt = rtq9124_dai_set_format, + .set_tdm_slot = rtq9124_dai_set_tdm_slot, + .hw_params = rtq9124_dai_hw_params, +}; + +static struct snd_soc_dai_driver rtq9124_dai_driver = { + .name = "HiFi", + .playback = { + .stream_name = "HiFi Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_24000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &rtq9124_dai_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, +}; + +static bool rtq9124_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x17: + case 0x20 ... 0x27: + case 0x30 ... 0x3D: + case 0x40 ... 0x68: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static bool rtq9124_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x09: + case 0x0C ... 0x0E: + case 0x10 ... 0x17: + case 0x20 ... 0x27: + case 0x30: + case 0x32 ... 0x3D: + case 0x40 ... 0x4E: + case 0x50 ... 0x68: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static bool rtq9124_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0A ... 0x0B: + case 0x0F ... 0x17: + case 0x31: + case 0x4F: + case 0x51: + case 0x53 ... 0x57: + case 0x80 ... 0xBC: + case 0xC0 ... 0xDE: + case 0xE0 ... 0xE7: + case 0xF0 ... 0xFD: + return true; + default: + return false; + } +} + +static inline u8 rtq9124_get_reg_len(unsigned int reg) +{ + return (reg >= 0x40 && reg <= 0x47) ? 4 : 2; +} + +static int rtq9124_regmap_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, + size_t val_size) +{ + struct i2c_client *i2c = context; + u8 reg = *(u8 *)reg_buf; + u8 size = rtq9124_get_reg_len(reg); + u32 *val = val_buf; + int ret; + + ret = i2c_smbus_read_i2c_block_data(i2c, reg, size, val_buf); + if (ret < 0) + return ret; + else if (ret != size) + return -EIO; + + *val = size == 4 ? be32_to_cpup(val_buf) : be16_to_cpup(val_buf); + + return 0; +} + +static int rtq9124_regmap_write(void *context, const void *data, size_t count) +{ + struct i2c_client *i2c = context; + u8 reg = *(u8 *)data, *vbuf; + u8 size = rtq9124_get_reg_len(reg); + __be16 val16 = cpu_to_be16p(data + 1); + __be32 val32 = cpu_to_be32p(data + 1); + + vbuf = size == 4 ? (u8 *)&val32 : (u8 *)&val16; + return i2c_smbus_write_i2c_block_data(i2c, reg, size, vbuf); +} + +static const struct regmap_config rtq9124_regmap_config = { + .name = "rtq9124", + .reg_bits = 8, + .val_bits = 32, + .read = rtq9124_regmap_read, + .write = rtq9124_regmap_write, + .readable_reg = rtq9124_readable_reg, + .writeable_reg = rtq9124_writeable_reg, + .volatile_reg = rtq9124_volatile_reg, + .cache_type = REGCACHE_MAPLE, + .num_reg_defaults_raw = 0xFD + 1, + .use_single_read = 1, + .use_single_write = 1, +}; + +static const struct reg_sequence rtq9124_init_regs[] = { + { 0xfb, 0x0065 }, + { 0x93, 0x2000 }, + { 0xfb, 0x0000 }, +}; + +static int rtq9124_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct rtq9124_priv *rtq9124; + struct regmap *regmap; + int ret; + + rtq9124 = devm_kzalloc(dev, sizeof(*rtq9124), GFP_KERNEL); + if (!rtq9124) + return -ENOMEM; + + rtq9124->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(rtq9124->enable)) + return PTR_ERR(rtq9124->enable); + else if (rtq9124->enable) + usleep_range(6000, 7000); + else + dev_dbg(dev, "No 'enable' GPIO specified, treat it as default on\n"); + + /* Check vendor id information */ + ret = i2c_smbus_read_word_swapped(i2c, RTQ9124_REG_PRJ_CODE); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to read project code\n"); + else if (ret != RTQ9124_FIXED_VENID) + return dev_err_probe(dev, -ENODEV, "Incorrect project-code 0x%04x\n", ret); + + /* Trigger RG reset before regmap init */ + ret = i2c_smbus_write_word_swapped(i2c, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_SF_RESET); + if (ret) + return dev_err_probe(dev, ret, "Failed to trigger RG reset\n"); + + /* Need to wait 10ms for the reset to complete */ + usleep_range(10000, 11000); + + regmap = devm_regmap_init(dev, NULL, i2c, &rtq9124_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n"); + + ret = regmap_register_patch(regmap, rtq9124_init_regs, ARRAY_SIZE(rtq9124_init_regs)); + if (ret) + return dev_err_probe(dev, ret, "Failed to register regmap patch\n"); + + i2c_set_clientdata(i2c, rtq9124); + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + return devm_snd_soc_register_component(dev, &rtq9124_comp_driver, &rtq9124_dai_driver, 1); +} + +#ifdef CONFIG_PM +static int rtq9124_runtime_suspend(struct device *dev) +{ + struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev); + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (rtq9124->enable) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + gpiod_set_value(rtq9124->enable, 0); + } + + return 0; +} + +static int rtq9124_runtime_resume(struct device *dev) +{ + struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev); + struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; + + if (rtq9124->enable) { + gpiod_set_value(rtq9124->enable, 1); + usleep_range(6000, 7000); + + regcache_cache_only(regmap, false); + ret = regcache_sync(regmap); + if (ret) + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops rtq9124_dev_pm_ops = { + SET_RUNTIME_PM_OPS(rtq9124_runtime_suspend, rtq9124_runtime_resume, NULL) +}; + +#ifdef CONFIG_OF +static const struct of_device_id rtq9124_device_id[] = { + { .compatible = "richtek,rtq9124" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtq9124_device_id); +#endif + +static struct i2c_driver rtq9124_driver = { + .driver = { + .name = "rtq9124", + .of_match_table = of_match_ptr(rtq9124_device_id), + .pm = pm_ptr(&rtq9124_dev_pm_ops), + }, + .probe = rtq9124_probe, +}; +module_i2c_driver(rtq9124_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("ASoC RTQ9124 Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 6bf37c77f0a7..41d73f470f8b 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -839,6 +839,56 @@ static const struct tas571x_chip tas5733_chip = { .vol_reg_size = 2, }; +static const struct reg_default tas5753_reg_defaults[] = { + {TAS571X_CLK_CTRL_REG, 0x6c}, + {TAS571X_DEV_ID_REG, 0x41}, + {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, 0x03ff}, + {TAS571X_CH1_VOL_REG, 0x00c0}, + {TAS571X_CH2_VOL_REG, 0x00c0}, + {TAS571X_CH3_VOL_REG, 0x00c0}, + {TAS571X_VOL_CFG_REG, 0xf0}, + {TAS571X_MODULATION_LIMIT_REG, 0x01}, + {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_OSC_TRIM_REG, 0x82}, + {TAS571X_BKND_ERR_REG, 0x57}, + {TAS571X_INPUT_MUX_REG, 0x00017772}, + {TAS571X_PWM_MUX_REG, 0x01021345}, + {TAS5717_CH1_RIGHT_CH_MIX_REG, 0x00}, + {TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000}, + {TAS5717_CH2_LEFT_CH_MIX_REG, 0x00}, + {TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000}, +}; + +static const struct regmap_config tas5753_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .max_register = 0xff, + .reg_read = tas571x_reg_read, + .reg_write = tas571x_reg_write, + .reg_defaults = tas5753_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas5753_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .wr_table = &tas571x_write_regs, + .volatile_table = &tas571x_volatile_regs, +}; + +static const struct tas571x_chip tas5753_chip = { + .supply_names = tas5721_supply_names, + .num_supply_names = ARRAY_SIZE(tas5721_supply_names), + .controls = tas5733_controls, + .num_controls = ARRAY_SIZE(tas5733_controls), + .regmap_config = &tas5753_regmap_config, + .vol_reg_size = 2, +}; + static const struct tas571x_chip tas5721_chip = { .supply_names = tas5721_supply_names, .num_supply_names = ARRAY_SIZE(tas5721_supply_names), @@ -1007,6 +1057,7 @@ static const struct of_device_id tas571x_of_match[] __maybe_unused = { { .compatible = "ti,tas5719", .data = &tas5717_chip, }, { .compatible = "ti,tas5721", .data = &tas5721_chip, }, { .compatible = "ti,tas5733", .data = &tas5733_chip, }, + { .compatible = "ti,tas5753", .data = &tas5753_chip, }, { } }; MODULE_DEVICE_TABLE(of, tas571x_of_match); @@ -1018,6 +1069,7 @@ static const struct i2c_device_id tas571x_i2c_id[] = { { "tas5719", (kernel_ulong_t) &tas5717_chip }, { "tas5721", (kernel_ulong_t) &tas5721_chip }, { "tas5733", (kernel_ulong_t) &tas5733_chip }, + { "tas5753", (kernel_ulong_t) &tas5753_chip }, { } }; MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 126a29e0b3ff..a5cf6015122c 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -89,7 +89,7 @@ struct wcd937x_priv { struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; + struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD937X_MAX_MICBIAS]; s32 pullup_ref[WCD937X_MAX_MICBIAS]; @@ -111,6 +111,10 @@ struct wcd937x_priv { atomic_t ana_clk_count; }; +static const char * const wcd937x_supplies[] = { + "vdd-rxtx", "vdd-px", "vdd-mic-bias", "vdd-buck", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -2932,18 +2936,10 @@ static int wcd937x_probe(struct platform_device *pdev) cfg = &wcd937x->mbhc_cfg; cfg->swap_gnd_mic = wcd937x_swap_gnd_mic; - wcd937x->supplies[0].supply = "vdd-rxtx"; - wcd937x->supplies[1].supply = "vdd-px"; - wcd937x->supplies[2].supply = "vdd-mic-bias"; - wcd937x->supplies[3].supply = "vdd-buck"; - - ret = devm_regulator_bulk_get(dev, WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd937x_supplies), + wcd937x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd937x_dt_parse_micbias_info(dev, wcd937x); @@ -2960,13 +2956,13 @@ static int wcd937x_probe(struct platform_device *pdev) ret = wcd937x_add_slave_components(wcd937x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd937x_reset(wcd937x); ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -2976,25 +2972,17 @@ static int wcd937x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - - return ret; } static void wcd937x_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct wcd937x_priv *wcd937x = dev_get_drvdata(dev); component_master_del(&pdev->dev, &wcd937x_comp_ops); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_dont_use_autosuspend(dev); - - regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 4ef57c496c37..3ab21bb5846e 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -487,7 +487,6 @@ #define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31) #define WCD937X_MAX_MICBIAS 3 -#define WCD937X_MAX_BULK_SUPPLY 4 #define WCD937X_MAX_SWR_CH_IDS 15 #define WCD937X_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 5a751056a98a..6401ac32d1b6 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -26,7 +26,6 @@ #include "wcd938x.h" #define WCD938X_MAX_MICBIAS (4) -#define WCD938X_MAX_SUPPLY (4) #define WCD938X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) @@ -160,7 +159,7 @@ struct wcd938x_priv { struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; + struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD938X_MAX_MICBIAS]; s32 pullup_ref[WCD938X_MAX_MICBIAS]; @@ -185,6 +184,10 @@ struct wcd938x_priv { bool mux_setup_done; }; +static const char * const wcd938x_supplies[] = { + "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, 0); static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); @@ -3290,20 +3293,10 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device cfg->swap_gnd_mic = wcd938x_swap_gnd_mic; - wcd938x->supplies[0].supply = "vdd-rxtx"; - wcd938x->supplies[1].supply = "vdd-io"; - wcd938x->supplies[2].supply = "vdd-buck"; - wcd938x->supplies[3].supply = "vdd-mic-bias"; - - ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd938x_supplies), + wcd938x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - if (ret) { - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd938x_dt_parse_micbias_info(dev, wcd938x); @@ -3567,13 +3560,13 @@ static int wcd938x_probe(struct platform_device *pdev) ret = wcd938x_add_slave_components(wcd938x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd938x_reset(wcd938x); ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -3583,12 +3576,6 @@ static int wcd938x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); - - return ret; } static void wcd938x_remove(struct platform_device *pdev) @@ -3604,9 +3591,6 @@ static void wcd938x_remove(struct platform_device *pdev) if (wcd938x->us_euro_mux && wcd938x->mux_setup_done) mux_control_deselect(wcd938x->us_euro_mux); - - regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies); - regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index bfd4d2c8bdc9..45645abe3085 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -32,7 +32,6 @@ #include "wcd939x.h" #define WCD939X_MAX_MICBIAS (4) -#define WCD939X_MAX_SUPPLY (4) #define WCD939X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) #define WCD_MBHC_HS_V_MAX 1600 @@ -191,7 +190,7 @@ struct wcd939x_priv { struct wcd_clsh_ctrl *clsh_info; struct irq_domain *virq; struct regmap_irq_chip_data *irq_chip; - struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; + struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD939X_MAX_MICBIAS]; s32 pullup_ref[WCD939X_MAX_MICBIAS]; @@ -211,6 +210,10 @@ struct wcd939x_priv { bool ldoh; }; +static const char * const wcd939x_supplies[] = { + "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", "vdd-px", +}; + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -3237,25 +3240,14 @@ static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device int ret; wcd939x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(wcd939x->reset_gpio)) { - ret = PTR_ERR(wcd939x->reset_gpio); - return dev_err_probe(dev, ret, "Failed to get reset gpio\n"); - } - - wcd939x->supplies[0].supply = "vdd-rxtx"; - wcd939x->supplies[1].supply = "vdd-io"; - wcd939x->supplies[2].supply = "vdd-buck"; - wcd939x->supplies[3].supply = "vdd-mic-bias"; + if (IS_ERR(wcd939x->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd939x->reset_gpio), + "Failed to get reset gpio\n"); - ret = regulator_bulk_get(dev, WCD939X_MAX_SUPPLY, wcd939x->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd939x_supplies), + wcd939x_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); - - ret = regulator_bulk_enable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - if (ret) { - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); - return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); wcd939x_dt_parse_micbias_info(dev, wcd939x); @@ -3627,17 +3619,17 @@ static int wcd939x_probe(struct platform_device *pdev) ret = wcd939x_add_typec(wcd939x, dev); if (ret) - goto err_disable_regulators; + return ret; ret = wcd939x_add_slave_components(wcd939x, dev, &match); if (ret) - goto err_disable_regulators; + return ret; wcd939x_reset(wcd939x); ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match); if (ret) - goto err_disable_regulators; + return ret; pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); @@ -3647,27 +3639,17 @@ static int wcd939x_probe(struct platform_device *pdev) pm_runtime_idle(dev); return 0; - -err_disable_regulators: - regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); - - return ret; } static void wcd939x_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); component_master_del(dev, &wcd939x_comp_ops); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_dont_use_autosuspend(dev); - - regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); - regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 9e668ae68039..ea5dbb54b584 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -513,7 +513,6 @@ static int imx_card_parse_of(struct imx_card_data *data) struct device_node *platform = NULL; struct device_node *codec = NULL; struct device_node *cpu = NULL; - struct device_node *np; struct device *dev = card->dev; struct snd_soc_dai_link *link; struct dai_link_data *link_data; @@ -552,11 +551,10 @@ static int imx_card_parse_of(struct imx_card_data *data) link = card->dai_link; link_data = data->link_data; - for_each_child_of_node(dev->of_node, np) { + for_each_child_of_node_scoped(dev->of_node, np) { dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); if (!dlc) { - ret = -ENOMEM; - goto err_put_np; + return -ENOMEM; } link->cpus = &dlc[0]; @@ -567,8 +565,8 @@ static int imx_card_parse_of(struct imx_card_data *data) ret = of_property_read_string(np, "link-name", &link->name); if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); - goto err_put_np; + return dev_err_probe(card->dev, ret, + "error getting codec dai_link name\n"); } cpu = of_get_child_by_name(np, "cpu"); @@ -725,8 +723,7 @@ err: of_node_put(cpu); of_node_put(codec); of_node_put(platform); -err_put_np: - of_node_put(np); + return ret; } diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 673ccf162023..fb49167f5fc4 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -309,6 +309,33 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { .tplg_filename = "rt1308-tplg.bin", }, { + .id = "10EC5640", + .uid = "1", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt5640-tplg.bin", + }, + { + .id = "10EC5640", + .uid = "3", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt5640-tplg.bin", + }, + { + .id = "10EC5640", + .uid = "2", + .drv_name = "avs_rt5640", + .mach_params = { + .i2s_link_mask = AVS_SSP(2), + }, + .tplg_filename = "rt5640-tplg.bin", + }, + { .id = "ESSX8336", .drv_name = "avs_es8336", .mach_params = { diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index 8b654181004e..82f50207bb2f 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -153,6 +153,18 @@ config SND_SOC_INTEL_AVS_MACH_RT5514 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_RT5640 + tristate "rt5640 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5640 + help + This adds support for ASoC machine board connecting AVS with RT5640, + components representing Intel AudioDSP and Realtek 5640 codec respectively. + The codec chip is present on I2C bus and the streaming occurs over I2S + interface. + Say Y or m if you have such a device. + config SND_SOC_INTEL_AVS_MACH_RT5663 tristate "rt5663 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index a95256b94dc8..46ef1babda34 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -15,6 +15,7 @@ snd-soc-avs-rt274-y := rt274.o snd-soc-avs-rt286-y := rt286.o snd-soc-avs-rt298-y := rt298.o snd-soc-avs-rt5514-y := rt5514.o +snd-soc-avs-rt5640-y := rt5640.o snd-soc-avs-rt5663-y := rt5663.o snd-soc-avs-rt5682-y := rt5682.o snd-soc-avs-ssm4567-y := ssm4567.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5514) += snd-soc-avs-rt5514.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5640) += snd-soc-avs-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c new file mode 100644 index 000000000000..706b84ffe1ef --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5640.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022-2025 Intel Corporation +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt5640.h" +#include "../utils.h" + +#define AVS_RT5640_MCLK_HZ 19200000 +#define RT5640_CODEC_DAI "rt5640-aif1" + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + { "Headphone Jack", NULL, "HPOR" }, + { "Headphone Jack", NULL, "HPOL" }, + { "IN2P", NULL, "Mic Jack" }, + { "IN2P", NULL, "MICBIAS1" }, + { "Speaker", NULL, "SPOLP" }, + { "Speaker", NULL, "SPOLN" }, + { "Speaker", NULL, "SPORP" }, + { "Speaker", NULL, "SPORN" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt5640_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins, + num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(codec_dai->component, jack, NULL); + card->dapm.idle_bias_off = true; + + return 0; +} + +static void avs_rt5640_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + + snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_rt5640_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* Format 24/32 is MSB-aligned for HDAudio and LSB-aligned for I2S. */ + if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) + snd_mask_set_format(fmask, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_rt5640_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + int ret; + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, AVS_RT5640_MCLK_HZ, + params_rate(params) * 512); + if (ret < 0) { + dev_err(runtime->dev, "Set codec PLL failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(runtime->dev, "Set codec SCLK failed: %d\n", ret); + return ret; + } + + ret = rt5640_sel_asrc_clk_src(codec_dai->component, + RT5640_DA_STEREO_FILTER | RT5640_AD_STEREO_FILTER | + RT5640_DA_MONO_L_FILTER | RT5640_DA_MONO_R_FILTER | + RT5640_AD_MONO_L_FILTER | RT5640_AD_MONO_R_FILTER, + RT5640_CLK_SEL_ASRC); + if (ret) + dev_err(runtime->dev, "Set codec ASRC failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_rt5640_ops = { + .hw_params = avs_rt5640_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_acpi_mach *mach, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + u32 uid = 0; + int ret; + + if (mach->uid) { + ret = kstrtou32(mach->uid, 0, &uid); + if (ret) + return ret; + uid--; /* 0-based indexing. */ + } + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot)); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5640:0%d", uid); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5640_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + platform->name = dev_name(dev); + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->init = avs_rt5640_codec_init; + dl->exit = avs_rt5640_codec_exit; + dl->be_hw_params_fixup = avs_rt5640_be_fixup; + dl->ops = &avs_rt5640_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, jack, NULL); +} + +static int avs_rt5640_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + int ssp_port, tdm_slot, ret; + + mach = dev_get_platdata(dev); + + ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); + if (ret) + return ret; + + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, mach, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + if (mach->uid) { + card->name = devm_kasprintf(dev, GFP_KERNEL, "AVS I2S ALC5640.%s", mach->uid); + if (!card->name) + return -ENOMEM; + } else { + card->name = "AVS I2S ALC5640"; + } + card->driver_name = "avs_rt5640"; + card->long_name = card->name; + card->dev = dev; + card->owner = THIS_MODULE; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + return devm_snd_soc_register_deferrable_card(dev, card); +} + +static const struct platform_device_id avs_rt5640_driver_ids[] = { + { + .name = "avs_rt5640", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); + +static struct platform_driver avs_rt5640_driver = { + .probe = avs_rt5640_probe, + .driver = { + .name = "avs_rt5640", + .pm = &snd_soc_pm_ops, + }, + .id_table = avs_rt5640_driver_ids, +}; + +module_platform_driver(avs_rt5640_driver); + +MODULE_DESCRIPTION("Intel rt5640 machine driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index a2dfccb7990f..b4dca80e15e4 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -222,7 +222,6 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, struct axg_dai_link_tdm_data *be) { struct axg_dai_link_tdm_mask *codec_mask; - struct device_node *np; codec_mask = devm_kcalloc(card->dev, link->num_codecs, sizeof(*codec_mask), GFP_KERNEL); @@ -231,7 +230,7 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, be->codec_masks = codec_mask; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", &codec_mask->rx); snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 68531183fb60..cdb759b466ad 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -137,7 +137,6 @@ int meson_card_set_be_link(struct snd_soc_card *card, struct device_node *node) { struct snd_soc_dai_link_component *codec; - struct device_node *np; int ret, num_codecs; num_codecs = of_get_child_count(node); @@ -154,19 +153,17 @@ int meson_card_set_be_link(struct snd_soc_card *card, link->codecs = codec; link->num_codecs = num_codecs; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ret = meson_card_parse_dai(card, np, codec); - if (ret) { - of_node_put(np); + if (ret) return ret; - } codec++; } ret = meson_card_set_link_name(card, link, node, "be"); if (ret) - dev_err(card->dev, "error setting %pOFn link name\n", np); + dev_err(card->dev, "error setting %pOFn link name\n", node); return ret; } @@ -198,7 +195,6 @@ static int meson_card_add_links(struct snd_soc_card *card) { struct meson_card *priv = snd_soc_card_get_drvdata(card); struct device_node *node = card->dev->of_node; - struct device_node *np; int num, i, ret; num = of_get_child_count(node); @@ -212,12 +208,10 @@ static int meson_card_add_links(struct snd_soc_card *card) return ret; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ret = priv->match_data->add_link(card, np, &i); - if (ret) { - of_node_put(np); + if (ret) return ret; - } i++; } diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 9946f12254b3..b456e096f138 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -202,7 +202,6 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, struct regmap *map; unsigned int dai_id = cpu_dai->driver->id; - component->id = dai_id; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1190,13 +1189,14 @@ static int lpass_platform_pcmops_suspend(struct snd_soc_component *component) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct regmap *map; - unsigned int dai_id = component->id; - if (dai_id == LPASS_DP_RX) + if (drvdata->hdmi_port_enable) { map = drvdata->hdmiif_map; - else - map = drvdata->lpaif_map; + regcache_cache_only(map, true); + regcache_mark_dirty(map); + } + map = drvdata->lpaif_map; regcache_cache_only(map, true); regcache_mark_dirty(map); @@ -1207,14 +1207,19 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); struct regmap *map; - unsigned int dai_id = component->id; + int ret; - if (dai_id == LPASS_DP_RX) + if (drvdata->hdmi_port_enable) { map = drvdata->hdmiif_map; - else - map = drvdata->lpaif_map; + regcache_cache_only(map, false); + ret = regcache_sync(map); + if (ret) + return ret; + } + map = drvdata->lpaif_map; regcache_cache_only(map, false); + return regcache_sync(map); } @@ -1224,7 +1229,9 @@ static int lpass_platform_copy(struct snd_soc_component *component, unsigned long bytes) { struct snd_pcm_runtime *rt = substream->runtime; - unsigned int dai_id = component->id; + struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + unsigned int dai_id = cpu_dai->driver->id; int ret = 0; void __iomem *dma_buf = (void __iomem *) (rt->dma_area + pos + diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index b70b2a5031df..69c514fad0b1 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -16,7 +16,6 @@ #include "usb_offload_utils.h" #include "sdw.h" -#define DRIVER_NAME "sm8250" #define MI2S_BCLK_RATE 1536000 struct sm8250_snd_data { @@ -26,6 +25,7 @@ struct sm8250_snd_data { struct snd_soc_jack jack; struct snd_soc_jack usb_offload_jack; bool usb_offload_jack_setup; + struct snd_soc_jack dp_jack; bool jack_setup; }; @@ -33,14 +33,16 @@ static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - int ret; - if (cpu_dai->id == USB_RX) - ret = qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack, - &data->usb_offload_jack_setup); - else - ret = qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); - return ret; + switch (cpu_dai->id) { + case DISPLAY_PORT_RX: + return qcom_snd_dp_jack_setup(rtd, &data->dp_jack, 0); + case USB_RX: + return qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack, + &data->usb_offload_jack_setup); + default: + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + } } static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd) @@ -200,15 +202,16 @@ static int sm8250_platform_probe(struct platform_device *pdev) if (ret) return ret; - card->driver_name = DRIVER_NAME; + card->driver_name = of_device_get_match_data(dev); sm8250_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } static const struct of_device_id snd_sm8250_dt_match[] = { - {.compatible = "qcom,sm8250-sndcard"}, - {.compatible = "qcom,qrb4210-rb2-sndcard"}, - {.compatible = "qcom,qrb5165-rb5-sndcard"}, + { .compatible = "fairphone,fp5-sndcard", .data = "qcm6490" }, + { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, + { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, + { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" }, {} }; diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index a72f36d3ca2c..37d954495ea5 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -1075,7 +1075,6 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); - struct device_node *np; int is_play = rsnd_io_is_play(io); int i; @@ -1094,7 +1093,7 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, if (!node) break; - for_each_child_of_node(ssiu_np, np) { + for_each_child_of_node_scoped(ssiu_np, np) { if (np == node) { rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); dev_dbg(dev, "%s is part of TDM Split\n", io->name); @@ -1154,21 +1153,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; int i; if (!node) return; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = mod_get(priv, i); @@ -1217,16 +1213,13 @@ int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *na int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; int i; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); + if (i < 0) return 0; - } i++; } @@ -1250,7 +1243,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct device_node *ports, *node; + struct device_node *node; int nr = 0; int i = 0; @@ -1270,7 +1263,7 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) of_node_put(node); - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (!of_node_name_eq(node, RSND_NODE_DAI)) continue; @@ -1279,7 +1272,6 @@ static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); - of_node_put(node); break; } } @@ -1290,7 +1282,7 @@ audio_graph: /* * Audio-Graph-Card */ - for_each_child_of_node(np, ports) { + for_each_child_of_node_scoped(np, ports) { node = rsnd_pick_endpoint_node_for_ports(ports, np); if (!node) continue; @@ -1299,7 +1291,6 @@ audio_graph: i++; if (i >= RSND_MAX_COMPONENT) { dev_info(dev, "reach to max component\n"); - of_node_put(ports); break; } } @@ -1505,10 +1496,9 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) dai_i = 0; if (is_graph) { struct device_node *dai_np_port; - struct device_node *ports; struct device_node *dai_np; - for_each_child_of_node(np, ports) { + for_each_child_of_node_scoped(np, ports) { dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np); if (!dai_np_port) continue; @@ -1525,14 +1515,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) } } } else { - struct device_node *node; - struct device_node *dai_np; - - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (!of_node_name_eq(node, RSND_NODE_DAI)) continue; - for_each_child_of_node(node, dai_np) { + for_each_child_of_node_scoped(node, dai_np) { __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { rdai = rsnd_rdai_get(priv, dai_i); diff --git a/sound/soc/renesas/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c index a26ec7b780cd..bd4c61f9fb3c 100644 --- a/sound/soc/renesas/rcar/ctu.c +++ b/sound/soc/renesas/rcar/ctu.c @@ -316,7 +316,6 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) int rsnd_ctu_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ctu *ctu; struct clk *clk; @@ -344,7 +343,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { ctu = rsnd_ctu_get(priv, i); /* @@ -357,16 +356,13 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_ctu_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, clk, RSND_MOD_CTU, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_ctu_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/dma.c b/sound/soc/renesas/rcar/dma.c index 2342bbb6fe92..2035ce06fe4c 100644 --- a/sound/soc/renesas/rcar/dma.c +++ b/sound/soc/renesas/rcar/dma.c @@ -194,14 +194,12 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *nam struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct dma_chan *chan = NULL; - struct device_node *np; int i = 0; - for_each_child_of_node(of_node, np) { + for_each_child_of_node_scoped(of_node, np) { i = rsnd_node_fixed_index(dev, np, name, i); if (i < 0) { chan = NULL; - of_node_put(np); break; } diff --git a/sound/soc/renesas/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c index da91dd301aab..988cbddbc611 100644 --- a/sound/soc/renesas/rcar/dvc.c +++ b/sound/soc/renesas/rcar/dvc.c @@ -324,7 +324,6 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) int rsnd_dvc_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dvc *dvc; struct clk *clk; @@ -352,7 +351,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { dvc = rsnd_dvc_get(priv, i); snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", @@ -361,16 +360,13 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_dvc_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, clk, RSND_MOD_DVC, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_dvc_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/mix.c b/sound/soc/renesas/rcar/mix.c index 024d91cc8748..aea74e703305 100644 --- a/sound/soc/renesas/rcar/mix.c +++ b/sound/soc/renesas/rcar/mix.c @@ -288,7 +288,6 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) int rsnd_mix_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mix *mix; struct clk *clk; @@ -316,7 +315,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) i = 0; ret = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { mix = rsnd_mix_get(priv, i); snprintf(name, MIX_NAME_SIZE, "%s.%d", @@ -325,16 +324,13 @@ int rsnd_mix_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_mix_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, clk, RSND_MOD_MIX, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_mix_probe_done; - } i++; } diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c index 75c9e91bada1..36d31ab8ac6a 100644 --- a/sound/soc/renesas/rcar/msiof.c +++ b/sound/soc/renesas/rcar/msiof.c @@ -30,56 +30,15 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/spi/sh_msiof.h> #include <sound/dmaengine_pcm.h> #include <sound/soc.h> -/* register */ -#define SITMDR1 0x00 -#define SITMDR2 0x04 -#define SITMDR3 0x08 -#define SIRMDR1 0x10 -#define SIRMDR2 0x14 -#define SIRMDR3 0x18 -#define SICTR 0x28 -#define SISTR 0x40 -#define SIIER 0x44 -#define SITFDR 0x50 -#define SIRFDR 0x60 - -/* SITMDR1/ SIRMDR1 */ -#define PCON (1 << 30) /* Transfer Signal Connection */ -#define SYNCMD_LR (3 << 28) /* L/R mode */ -#define SYNCAC (1 << 25) /* Sync Polarity (Active-low) */ -#define DTDL_1 (1 << 20) /* 1-clock-cycle delay */ -#define TXSTP (1 << 0) /* Transmission/Reception Stop on FIFO */ - -/* SITMDR2 and SIRMDR2 */ -#define BITLEN1(x) (((x) - 1) << 24) /* Data Size (8-32 bits) */ -#define GRP (1 << 30) /* Group count */ - -/* SICTR */ -#define TEDG (1 << 27) /* Transmit Timing (1 = falling edge) */ -#define REDG (1 << 26) /* Receive Timing (1 = rising edge) */ -#define TXE (1 << 9) /* Transmit Enable */ -#define RXE (1 << 8) /* Receive Enable */ - /* SISTR */ -#define TFSERR (1 << 21) /* Transmit Frame Synchronization Error */ -#define TFOVF (1 << 20) /* Transmit FIFO Overflow */ -#define TFUDF (1 << 19) /* Transmit FIFO Underflow */ -#define RFSERR (1 << 5) /* Receive Frame Synchronization Error */ -#define RFUDF (1 << 4) /* Receive FIFO Underflow */ -#define RFOVF (1 << 3) /* Receive FIFO Overflow */ -#define SISTR_ERR_TX (TFSERR | TFOVF | TFUDF) -#define SISTR_ERR_RX (RFSERR | RFOVF | RFUDF) +#define SISTR_ERR_TX (SISTR_TFSERR | SISTR_TFOVF | SISTR_TFUDF) +#define SISTR_ERR_RX (SISTR_RFSERR | SISTR_RFOVF | SISTR_RFUDF) #define SISTR_ERR (SISTR_ERR_TX | SISTR_ERR_RX) -/* SIIER */ -#define TDMAE (1 << 31) /* Transmit Data DMA Transfer Req. Enable */ -#define TDREQE (1 << 28) /* Transmit Data Transfer Request Enable */ -#define RDMAE (1 << 15) /* Receive Data DMA Transfer Req. Enable */ -#define RDREQE (1 << 12) /* Receive Data Transfer Request Enable */ - /* * The data on memory in 24bit case is located at <right> side * [ xxxxxx] @@ -174,42 +133,45 @@ static int msiof_hw_start(struct snd_soc_component *component, /* SITMDRx */ if (is_play) { - val = PCON | SYNCMD_LR | SYNCAC | TXSTP; + val = SITMDR1_PCON | + FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) | + SIMDR1_SYNCAC | SIMDR1_XXSTP; if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY)) - val |= DTDL_1; + val |= FIELD_PREP(SIMDR1_DTDL, 1); msiof_write(priv, SITMDR1, val); - val = BITLEN1(width); - msiof_write(priv, SITMDR2, val | GRP); + val = FIELD_PREP(SIMDR2_BITLEN1, width - 1); + msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1)); msiof_write(priv, SITMDR3, val); } /* SIRMDRx */ else { - val = SYNCMD_LR | SYNCAC; + val = FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) | + SIMDR1_SYNCAC; if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY)) - val |= DTDL_1; + val |= FIELD_PREP(SIMDR1_DTDL, 1); msiof_write(priv, SIRMDR1, val); - val = BITLEN1(width); - msiof_write(priv, SIRMDR2, val | GRP); + val = FIELD_PREP(SIMDR2_BITLEN1, width - 1); + msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1)); msiof_write(priv, SIRMDR3, val); } /* SIIER */ if (is_play) - val = TDREQE | TDMAE | SISTR_ERR_TX; + val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX; else - val = RDREQE | RDMAE | SISTR_ERR_RX; + val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX; msiof_update(priv, SIIER, val, val); /* SICTR */ if (is_play) - val = TXE | TEDG; + val = SICTR_TXE | SICTR_TEDG; else - val = RXE | REDG; + val = SICTR_RXE | SICTR_REDG; msiof_update_and_wait(priv, SICTR, val, val, val); msiof_status_clear(priv); @@ -230,9 +192,9 @@ static int msiof_hw_stop(struct snd_soc_component *component, /* SIIER */ if (is_play) - val = TDREQE | TDMAE | SISTR_ERR_TX; + val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX; else - val = RDREQE | RDMAE | SISTR_ERR_RX; + val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX; msiof_update(priv, SIIER, val, 0); /* Stop DMAC */ @@ -240,9 +202,9 @@ static int msiof_hw_stop(struct snd_soc_component *component, /* SICTR */ if (is_play) - val = TXE; + val = SICTR_TXE; else - val = RXE; + val = SICTR_RXE; msiof_update_and_wait(priv, SICTR, val, 0, 0); /* indicate error status if exist */ @@ -478,22 +440,22 @@ static irqreturn_t msiof_interrupt(int irq, void *data) substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK]; if (substream && (sistr & SISTR_ERR_TX)) { // snd_pcm_stop_xrun(substream); - if (sistr & TFSERR) + if (sistr & SISTR_TFSERR) priv->err_syc[SNDRV_PCM_STREAM_PLAYBACK]++; - if (sistr & TFOVF) + if (sistr & SISTR_TFOVF) priv->err_ovf[SNDRV_PCM_STREAM_PLAYBACK]++; - if (sistr & TFUDF) + if (sistr & SISTR_TFUDF) priv->err_udf[SNDRV_PCM_STREAM_PLAYBACK]++; } substream = priv->substream[SNDRV_PCM_STREAM_CAPTURE]; if (substream && (sistr & SISTR_ERR_RX)) { // snd_pcm_stop_xrun(substream); - if (sistr & RFSERR) + if (sistr & SISTR_RFSERR) priv->err_syc[SNDRV_PCM_STREAM_CAPTURE]++; - if (sistr & RFOVF) + if (sistr & SISTR_RFOVF) priv->err_ovf[SNDRV_PCM_STREAM_CAPTURE]++; - if (sistr & RFUDF) + if (sistr & SISTR_RFUDF) priv->err_udf[SNDRV_PCM_STREAM_CAPTURE]++; } diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c index 7d73b183bda6..f47bf38c2f94 100644 --- a/sound/soc/renesas/rcar/src.c +++ b/sound/soc/renesas/rcar/src.c @@ -715,7 +715,6 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) int rsnd_src_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_src *src; struct clk *clk; @@ -742,14 +741,13 @@ int rsnd_src_probe(struct rsnd_priv *priv) priv->src = src; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { if (!of_device_is_available(np)) goto skip; i = rsnd_node_fixed_index(dev, np, SRC_NAME, i); if (i < 0) { ret = -EINVAL; - of_node_put(np); goto rsnd_src_probe_done; } @@ -761,23 +759,19 @@ int rsnd_src_probe(struct rsnd_priv *priv) src->irq = irq_of_parse_and_map(np, 0); if (!src->irq) { ret = -EINVAL; - of_node_put(np); goto rsnd_src_probe_done; } clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_src_probe_done; } ret = rsnd_mod_init(priv, rsnd_mod_get(src), &rsnd_src_ops, clk, RSND_MOD_SRC, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_src_probe_done; - } skip: i++; diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c index 0c6424a1fcac..d52056caa3ec 100644 --- a/sound/soc/renesas/rcar/ssi.c +++ b/sound/soc/renesas/rcar/ssi.c @@ -1115,7 +1115,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *node; - struct device_node *np; int i; node = rsnd_ssi_of_node(priv); @@ -1123,14 +1122,12 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, return; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = rsnd_ssi_mod_get(priv, i); @@ -1163,7 +1160,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) int rsnd_ssi_probe(struct rsnd_priv *priv) { struct device_node *node; - struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; struct clk *clk; @@ -1191,14 +1187,13 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) priv->ssi_nr = nr; i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { if (!of_device_is_available(np)) goto skip; i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); if (i < 0) { ret = -EINVAL; - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1210,7 +1205,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1223,7 +1217,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ssi->irq = irq_of_parse_and_map(np, 0); if (!ssi->irq) { ret = -EINVAL; - of_node_put(np); goto rsnd_ssi_probe_done; } @@ -1234,10 +1227,9 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, RSND_MOD_SSI, i); - if (ret) { - of_node_put(np); + if (ret) goto rsnd_ssi_probe_done; - } + skip: i++; } diff --git a/sound/soc/renesas/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c index 665e8b2db579..faf351126d57 100644 --- a/sound/soc/renesas/rcar/ssiu.c +++ b/sound/soc/renesas/rcar/ssiu.c @@ -478,17 +478,14 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, /* use rcar_sound,ssiu if exist */ if (node) { - struct device_node *np; int i = 0; - for_each_child_of_node(node, np) { + for_each_child_of_node_scoped(node, np) { struct rsnd_mod *mod; i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i); - if (i < 0) { - of_node_put(np); + if (i < 0) break; - } mod = rsnd_ssiu_mod_get(priv, i); diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 602f1ddfad00..0b9f54102d69 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -378,19 +378,9 @@ static void rockchip_sai_xfer_start(struct rk_sai_dev *sai, int stream) static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream) { unsigned int msk = 0, val = 0, clr = 0; - bool playback; - bool capture; - - if (stream < 0) { - playback = true; - capture = true; - } else if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - playback = true; - capture = false; - } else { - playback = true; - capture = false; - } + bool capture = stream == SNDRV_PCM_STREAM_CAPTURE || stream < 0; + bool playback = stream == SNDRV_PCM_STREAM_PLAYBACK || stream < 0; + /* could be <= 0 but we don't want to depend on enum values */ if (playback) { msk |= SAI_XFER_TXS_MASK; @@ -1437,43 +1427,32 @@ static int rockchip_sai_probe(struct platform_device *pdev) if (irq > 0) { ret = devm_request_irq(&pdev->dev, irq, rockchip_sai_isr, IRQF_SHARED, node->name, sai); - if (ret) { + if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to request irq %d\n", irq); - } } else { dev_dbg(&pdev->dev, "Asked for an IRQ but got %d\n", irq); } sai->mclk = devm_clk_get(&pdev->dev, "mclk"); - if (IS_ERR(sai->mclk)) { + if (IS_ERR(sai->mclk)) return dev_err_probe(&pdev->dev, PTR_ERR(sai->mclk), "Failed to get mclk\n"); - } - sai->hclk = devm_clk_get(&pdev->dev, "hclk"); - if (IS_ERR(sai->hclk)) { + sai->hclk = devm_clk_get_enabled(&pdev->dev, "hclk"); + if (IS_ERR(sai->hclk)) return dev_err_probe(&pdev->dev, PTR_ERR(sai->hclk), "Failed to get hclk\n"); - } - - ret = clk_prepare_enable(sai->hclk); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to enable hclk\n"); regmap_read(sai->regmap, SAI_VERSION, &sai->version); ret = rockchip_sai_init_dai(sai, res, &dai); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize DAI: %d\n", ret); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to initialize DAI\n"); ret = rockchip_sai_parse_paths(sai, node); - if (ret) { - dev_err(&pdev->dev, "Failed to parse paths: %d\n", ret); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to parse paths\n"); /* * From here on, all register accesses need to be wrapped in @@ -1484,10 +1463,8 @@ static int rockchip_sai_probe(struct platform_device *pdev) devm_pm_runtime_enable(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); ret = rockchip_sai_runtime_resume(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Failed to resume device: %pe\n", ERR_PTR(ret)); - goto err_disable_hclk; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to resume device\n"); ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { @@ -1514,8 +1491,6 @@ err_runtime_suspend: /* If we're !CONFIG_PM, we get -ENOSYS and disable manually */ if (pm_runtime_put(&pdev->dev)) rockchip_sai_runtime_suspend(&pdev->dev); -err_disable_hclk: - clk_disable_unprepare(sai->hclk); return ret; } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 67bebc339148..cfafdabcdc88 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2604,6 +2604,7 @@ static char *fmt_single_name(struct device *dev, int *id) const char *devname = dev_name(dev); char *found, *name; unsigned int id1, id2; + int __id; if (devname == NULL) return NULL; @@ -2616,10 +2617,10 @@ static char *fmt_single_name(struct device *dev, int *id) found = strstr(name, dev->driver->name); if (found) { /* get ID */ - if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { + if (sscanf(&found[strlen(dev->driver->name)], ".%d", &__id) == 1) { /* discard ID from name if ID == -1 */ - if (*id == -1) + if (__id == -1) found[strlen(dev->driver->name)] = '\0'; } @@ -2627,16 +2628,19 @@ static char *fmt_single_name(struct device *dev, int *id) } else if (sscanf(name, "%x-%x", &id1, &id2) == 2) { /* create unique ID number from I2C addr and bus */ - *id = ((id1 & 0xffff) << 16) + id2; + __id = ((id1 & 0xffff) << 16) + id2; devm_kfree(dev, name); /* sanitize component name for DAI link creation */ name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", dev->driver->name, devname); } else { - *id = 0; + __id = 0; } + if (id) + *id = __id; + return name; } @@ -2831,7 +2835,7 @@ int snd_soc_component_initialize(struct snd_soc_component *component, mutex_init(&component->io_mutex); if (!component->name) { - component->name = fmt_single_name(dev, &component->id); + component->name = fmt_single_name(dev, NULL); if (!component->name) { dev_err(dev, "ASoC: Failed to allocate name\n"); return -ENOMEM; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index a210089747d0..32f46a38682b 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -259,13 +259,15 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, &rx_mask, }; - if (dai->driver->ops && - dai->driver->ops->xlate_tdm_slot_mask) - ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - else - ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - if (ret) - goto err; + if (slots) { + if (dai->driver->ops && + dai->driver->ops->xlate_tdm_slot_mask) + ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + else + ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + if (ret) + goto err; + } for_each_pcm_streams(stream) snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); |