Path: blob/master/sound/hda/codecs/side-codecs/cs35l56_hda.c
26481 views
// SPDX-License-Identifier: GPL-2.0-only1//2// HDA audio driver for Cirrus Logic CS35L56 smart amp3//4// Copyright (C) 2023 Cirrus Logic, Inc. and5// Cirrus Logic International Semiconductor Ltd.6//78#include <linux/acpi.h>9#include <linux/debugfs.h>10#include <linux/gpio/consumer.h>11#include <linux/module.h>12#include <linux/pm_runtime.h>13#include <linux/regmap.h>14#include <linux/slab.h>15#include <sound/core.h>16#include <sound/cs-amp-lib.h>17#include <sound/hda_codec.h>18#include <sound/tlv.h>19#include "cirrus_scodec.h"20#include "cs35l56_hda.h"21#include "hda_component.h"22#include "../generic.h"2324/*25* The cs35l56_hda_dai_config[] reg sequence configures the device as26* ASP1_BCLK_FREQ = 3.072 MHz27* ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S28* ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots29* ASP1_RX_WL = 24 bits per sample30* ASP1_TX_WL = 24 bits per sample31* ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled32*33* Override any Windows-specific mixer settings applied by the firmware.34*/35static const struct reg_sequence cs35l56_hda_dai_config[] = {36{ CS35L56_ASP1_CONTROL1, 0x00000021 },37{ CS35L56_ASP1_CONTROL2, 0x20200200 },38{ CS35L56_ASP1_CONTROL3, 0x00000003 },39{ CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },40{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },41{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },42{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },43{ CS35L56_ASP1_ENABLES1, 0x00000000 },44{ CS35L56_ASP1TX1_INPUT, 0x00000018 },45{ CS35L56_ASP1TX2_INPUT, 0x00000019 },46{ CS35L56_ASP1TX3_INPUT, 0x00000020 },47{ CS35L56_ASP1TX4_INPUT, 0x00000028 },4849};5051static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56)52{53/* Wait for patching to complete */54flush_work(&cs35l56->dsp_work);55}5657static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)58{59unsigned int val;60int ret;6162cs35l56_hda_wait_dsp_ready(cs35l56);6364pm_runtime_get_sync(cs35l56->base.dev);65ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);66if (ret == 0) {67/* Wait for firmware to enter PS0 power state */68ret = regmap_read_poll_timeout(cs35l56->base.regmap,69cs35l56->base.fw_reg->transducer_actual_ps,70val, (val == CS35L56_PS0),71CS35L56_PS0_POLL_US,72CS35L56_PS0_TIMEOUT_US);73if (ret)74dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);75}76regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,77BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |78cs35l56->asp_tx_mask);79cs35l56->playing = true;80}8182static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)83{84cs35l56->playing = false;85cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);86regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,87BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |88BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |89BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));9091pm_runtime_put_autosuspend(cs35l56->base.dev);92}9394static void cs35l56_hda_playback_hook(struct device *dev, int action)95{96struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);9798dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);99100switch (action) {101case HDA_GEN_PCM_ACT_PREPARE:102if (cs35l56->playing)103break;104105/* If we're suspended: flag that resume should start playback */106if (cs35l56->suspended) {107cs35l56->playing = true;108break;109}110111cs35l56_hda_play(cs35l56);112break;113case HDA_GEN_PCM_ACT_CLEANUP:114if (!cs35l56->playing)115break;116117cs35l56_hda_pause(cs35l56);118break;119default:120break;121}122}123124static int cs35l56_hda_runtime_suspend(struct device *dev)125{126struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);127128if (cs35l56->cs_dsp.booted)129cs_dsp_stop(&cs35l56->cs_dsp);130131return cs35l56_runtime_suspend_common(&cs35l56->base);132}133134static int cs35l56_hda_runtime_resume(struct device *dev)135{136struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);137int ret;138139ret = cs35l56_runtime_resume_common(&cs35l56->base, false);140if (ret < 0)141return ret;142143if (cs35l56->cs_dsp.booted) {144ret = cs_dsp_run(&cs35l56->cs_dsp);145if (ret) {146dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);147goto err;148}149}150151return 0;152153err:154cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);155regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,156CS35L56_MBOX_CMD_HIBERNATE_NOW);157158regcache_cache_only(cs35l56->base.regmap, true);159160return ret;161}162163static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,164struct snd_ctl_elem_info *uinfo)165{166uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;167uinfo->count = 1;168uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;169if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)170uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;171strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],172sizeof(uinfo->value.enumerated.name));173174return 0;175}176177static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,178struct snd_ctl_elem_value *ucontrol)179{180struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);181unsigned int reg_val;182int i;183184cs35l56_hda_wait_dsp_ready(cs35l56);185186regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val);187reg_val &= CS35L56_ASP_TXn_SRC_MASK;188189for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {190if (cs35l56_tx_input_values[i] == reg_val) {191ucontrol->value.enumerated.item[0] = i;192break;193}194}195196return 0;197}198199static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,200struct snd_ctl_elem_value *ucontrol)201{202struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);203unsigned int item = ucontrol->value.enumerated.item[0];204bool changed;205206if (item >= CS35L56_NUM_INPUT_SRC)207return -EINVAL;208209cs35l56_hda_wait_dsp_ready(cs35l56);210211regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,212CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],213&changed);214215return changed;216}217218static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,219struct snd_ctl_elem_info *uinfo)220{221uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;222uinfo->count = 1;223uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;224uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;225return 0;226}227228static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,229struct snd_ctl_elem_value *ucontrol)230{231struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);232unsigned int pos;233int ret;234235cs35l56_hda_wait_dsp_ready(cs35l56);236237ret = regmap_read(cs35l56->base.regmap,238cs35l56->base.fw_reg->posture_number, &pos);239if (ret)240return ret;241242ucontrol->value.integer.value[0] = pos;243244return 0;245}246247static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,248struct snd_ctl_elem_value *ucontrol)249{250struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);251unsigned long pos = ucontrol->value.integer.value[0];252bool changed;253int ret;254255if ((pos < CS35L56_MAIN_POSTURE_MIN) ||256(pos > CS35L56_MAIN_POSTURE_MAX))257return -EINVAL;258259cs35l56_hda_wait_dsp_ready(cs35l56);260261ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number,262CS35L56_MAIN_POSTURE_MASK, pos, &changed);263if (ret)264return ret;265266return changed;267}268269static const struct {270const char *name;271unsigned int reg;272} cs35l56_hda_mixer_controls[] = {273{ "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },274{ "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },275{ "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },276{ "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },277};278279static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);280281static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,282struct snd_ctl_elem_info *uinfo)283{284uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;285uinfo->count = 1;286uinfo->value.integer.step = 1;287uinfo->value.integer.min = 0;288uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -289CS35L56_MAIN_RENDER_USER_VOLUME_MIN;290291return 0;292}293294static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,295struct snd_ctl_elem_value *ucontrol)296{297struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);298unsigned int raw_vol;299int vol;300int ret;301302cs35l56_hda_wait_dsp_ready(cs35l56);303304ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol);305306if (ret)307return ret;308309vol = (s16)(raw_vol & 0xFFFF);310vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;311312if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))313vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));314315ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;316317return 0;318}319320static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,321struct snd_ctl_elem_value *ucontrol)322{323struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);324long vol = ucontrol->value.integer.value[0];325unsigned int raw_vol;326bool changed;327int ret;328329if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -330CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))331return -EINVAL;332333raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<334CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;335336cs35l56_hda_wait_dsp_ready(cs35l56);337338ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume,339CS35L56_MAIN_RENDER_USER_VOLUME_MASK, raw_vol, &changed);340if (ret)341return ret;342343return changed;344}345346static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)347{348struct snd_kcontrol_new ctl_template = {349.iface = SNDRV_CTL_ELEM_IFACE_MIXER,350.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,351.info = cs35l56_hda_posture_info,352.get = cs35l56_hda_posture_get,353.put = cs35l56_hda_posture_put,354};355char name[64];356int i;357358snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);359ctl_template.name = name;360cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);361if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))362dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);363364/* Mixer controls */365ctl_template.info = cs35l56_hda_mixer_info;366ctl_template.get = cs35l56_hda_mixer_get;367ctl_template.put = cs35l56_hda_mixer_put;368369BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));370371for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {372snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,373cs35l56_hda_mixer_controls[i].name);374ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;375cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);376if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {377dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",378ctl_template.name);379}380}381382ctl_template.info = cs35l56_hda_vol_info;383ctl_template.get = cs35l56_hda_vol_get;384ctl_template.put = cs35l56_hda_vol_put;385ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);386ctl_template.tlv.p = cs35l56_hda_vol_tlv;387snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);388ctl_template.name = name;389cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);390if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))391dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);392}393394static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)395{396int i;397398for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)399snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);400401snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);402snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);403}404405static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {406/* cs_dsp requires the client to provide this even if it is empty */407};408409static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,410const struct firmware **firmware, char **filename,411const char *base_name, const char *system_name,412const char *amp_name,413const char *filetype)414{415char *s, c;416int ret = 0;417418if (system_name && amp_name)419*filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,420system_name, amp_name, filetype);421else if (system_name)422*filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,423system_name, filetype);424else425*filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);426427if (!*filename)428return -ENOMEM;429430/*431* Make sure that filename is lower-case and any non alpha-numeric432* characters except full stop and forward slash are replaced with433* hyphens.434*/435s = *filename;436while (*s) {437c = *s;438if (isalnum(c))439*s = tolower(c);440else if (c != '.' && c != '/')441*s = '-';442s++;443}444445ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev);446if (ret) {447dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);448kfree(*filename);449*filename = NULL;450return ret;451}452453dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);454455return 0;456}457458static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,459unsigned int preloaded_fw_ver,460const struct firmware **wmfw_firmware,461char **wmfw_filename,462const struct firmware **coeff_firmware,463char **coeff_filename)464{465const char *system_name = cs35l56->system_name;466const char *amp_name = cs35l56->amp_name;467char base_name[37];468int ret;469470if (preloaded_fw_ver) {471snprintf(base_name, sizeof(base_name),472"cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",473cs35l56->base.type,474cs35l56->base.rev,475cs35l56->base.secured ? "-s" : "",476preloaded_fw_ver & 0xffffff);477} else {478snprintf(base_name, sizeof(base_name),479"cirrus/cs35l%02x-%02x%s-dsp1-misc",480cs35l56->base.type,481cs35l56->base.rev,482cs35l56->base.secured ? "-s" : "");483}484485if (system_name && amp_name) {486if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,487base_name, system_name, amp_name, "wmfw")) {488cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,489base_name, system_name, amp_name, "bin");490return;491}492}493494if (system_name) {495if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,496base_name, system_name, NULL, "wmfw")) {497if (amp_name)498cs35l56_hda_request_firmware_file(cs35l56,499coeff_firmware, coeff_filename,500base_name, system_name,501amp_name, "bin");502if (!*coeff_firmware)503cs35l56_hda_request_firmware_file(cs35l56,504coeff_firmware, coeff_filename,505base_name, system_name,506NULL, "bin");507return;508}509510/*511* Check for system-specific bin files without wmfw before512* falling back to generic firmware513*/514if (amp_name)515cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,516base_name, system_name, amp_name, "bin");517if (!*coeff_firmware)518cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,519base_name, system_name, NULL, "bin");520521if (*coeff_firmware)522return;523}524525ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,526base_name, NULL, NULL, "wmfw");527if (!ret) {528cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,529base_name, NULL, NULL, "bin");530return;531}532533if (!*coeff_firmware)534cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,535base_name, NULL, NULL, "bin");536}537538static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,539char *wmfw_filename,540const struct firmware *coeff_firmware,541char *coeff_filename)542{543release_firmware(wmfw_firmware);544kfree(wmfw_filename);545546release_firmware(coeff_firmware);547kfree(coeff_filename);548}549550static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)551{552int ret;553554if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)555return;556557ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,558&cs35l56_calibration_controls,559&cs35l56->base.cal_data);560if (ret < 0)561dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);562else563dev_info(cs35l56->base.dev, "Calibration applied\n");564}565566static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)567{568const struct firmware *coeff_firmware = NULL;569const struct firmware *wmfw_firmware = NULL;570char *coeff_filename = NULL;571char *wmfw_filename = NULL;572unsigned int preloaded_fw_ver;573bool firmware_missing;574int ret;575576/*577* Prepare for a new DSP power-up. If the DSP has had firmware578* downloaded previously then it needs to be powered down so that it579* can be updated.580*/581if (cs35l56->base.fw_patched)582cs_dsp_power_down(&cs35l56->cs_dsp);583584cs35l56->base.fw_patched = false;585586ret = pm_runtime_resume_and_get(cs35l56->base.dev);587if (ret < 0) {588dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);589return;590}591592/*593* The firmware can only be upgraded if it is currently running594* from the built-in ROM. If not, the wmfw/bin must be for the595* version of firmware that is running on the chip.596*/597ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);598if (ret)599goto err_pm_put;600601if (firmware_missing)602preloaded_fw_ver = 0;603604cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,605&wmfw_firmware, &wmfw_filename,606&coeff_firmware, &coeff_filename);607608/*609* If the BIOS didn't patch the firmware a bin file is mandatory to610* enable the ASPĀ·611*/612if (!coeff_firmware && firmware_missing) {613dev_err(cs35l56->base.dev, ".bin file required but not found\n");614goto err_fw_release;615}616617mutex_lock(&cs35l56->base.irq_lock);618619/*620* If the firmware hasn't been patched it must be shutdown before621* doing a full patch and reset afterwards. If it is already622* running a patched version the firmware files only contain623* tunings and we can use the lower cost reinit sequence instead.624*/625if (firmware_missing && (wmfw_firmware || coeff_firmware)) {626ret = cs35l56_firmware_shutdown(&cs35l56->base);627if (ret)628goto err;629}630631ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,632coeff_firmware, coeff_filename, "misc");633if (ret) {634dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);635goto err;636}637638if (wmfw_filename)639dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);640641if (coeff_filename)642dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);643644/* If we downloaded firmware, reset the device and wait for it to boot */645if (firmware_missing && (wmfw_firmware || coeff_firmware)) {646cs35l56_system_reset(&cs35l56->base, false);647regcache_mark_dirty(cs35l56->base.regmap);648ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);649if (ret)650goto err_powered_up;651652regcache_cache_only(cs35l56->base.regmap, false);653}654655/* Disable auto-hibernate so that runtime_pm has control */656ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);657if (ret)658goto err_powered_up;659660regcache_sync(cs35l56->base.regmap);661662regmap_clear_bits(cs35l56->base.regmap,663cs35l56->base.fw_reg->prot_sts,664CS35L56_FIRMWARE_MISSING);665cs35l56->base.fw_patched = true;666667ret = cs_dsp_run(&cs35l56->cs_dsp);668if (ret)669dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);670671cs35l56_hda_apply_calibration(cs35l56);672ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);673if (ret)674cs_dsp_stop(&cs35l56->cs_dsp);675676cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp);677678err_powered_up:679if (!cs35l56->base.fw_patched)680cs_dsp_power_down(&cs35l56->cs_dsp);681err:682mutex_unlock(&cs35l56->base.irq_lock);683err_fw_release:684cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,685coeff_firmware, coeff_filename);686err_pm_put:687pm_runtime_put(cs35l56->base.dev);688}689690static void cs35l56_hda_dsp_work(struct work_struct *work)691{692struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);693694cs35l56_hda_fw_load(cs35l56);695}696697static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)698{699struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);700struct hda_component_parent *parent = master_data;701struct hda_component *comp;702703comp = hda_component_from_index(parent, cs35l56->index);704if (!comp)705return -EINVAL;706707if (comp->dev)708return -EBUSY;709710comp->dev = dev;711cs35l56->codec = parent->codec;712strscpy(comp->name, dev_name(dev), sizeof(comp->name));713comp->playback_hook = cs35l56_hda_playback_hook;714715queue_work(system_long_wq, &cs35l56->dsp_work);716717cs35l56_hda_create_controls(cs35l56);718719#if IS_ENABLED(CONFIG_SND_DEBUG)720cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);721cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);722#endif723724dev_dbg(cs35l56->base.dev, "Bound\n");725726return 0;727}728729static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)730{731struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);732struct hda_component_parent *parent = master_data;733struct hda_component *comp;734735cancel_work_sync(&cs35l56->dsp_work);736737cs35l56_hda_remove_controls(cs35l56);738739#if IS_ENABLED(CONFIG_SND_DEBUG)740cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);741debugfs_remove_recursive(cs35l56->debugfs_root);742#endif743744if (cs35l56->base.fw_patched)745cs_dsp_power_down(&cs35l56->cs_dsp);746747comp = hda_component_from_index(parent, cs35l56->index);748if (comp && (comp->dev == dev))749memset(comp, 0, sizeof(*comp));750751cs35l56->codec = NULL;752753dev_dbg(cs35l56->base.dev, "Unbound\n");754}755756static const struct component_ops cs35l56_hda_comp_ops = {757.bind = cs35l56_hda_bind,758.unbind = cs35l56_hda_unbind,759};760761static int cs35l56_hda_system_suspend(struct device *dev)762{763struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);764765cs35l56_hda_wait_dsp_ready(cs35l56);766767if (cs35l56->playing)768cs35l56_hda_pause(cs35l56);769770cs35l56->suspended = true;771772/*773* The interrupt line is normally shared, but after we start suspending774* we can't check if our device is the source of an interrupt, and can't775* clear it. Prevent this race by temporarily disabling the parent irq776* until we reach _no_irq.777*/778if (cs35l56->base.irq)779disable_irq(cs35l56->base.irq);780781return pm_runtime_force_suspend(dev);782}783784static int cs35l56_hda_system_suspend_late(struct device *dev)785{786struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);787788/*789* RESET is usually shared by all amps so it must not be asserted until790* all driver instances have done their suspend() stage.791*/792if (cs35l56->base.reset_gpio) {793gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);794cs35l56_wait_min_reset_pulse();795}796797return 0;798}799800static int cs35l56_hda_system_suspend_no_irq(struct device *dev)801{802struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);803804/* Handlers are now disabled so the parent IRQ can safely be re-enabled. */805if (cs35l56->base.irq)806enable_irq(cs35l56->base.irq);807808return 0;809}810811static int cs35l56_hda_system_resume_no_irq(struct device *dev)812{813struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);814815/*816* WAKE interrupts unmask if the CS35L56 hibernates, which can cause817* spurious interrupts, and the interrupt line is normally shared.818* We can't check if our device is the source of an interrupt, and can't819* clear it, until it has fully resumed. Prevent this race by temporarily820* disabling the parent irq until we complete resume().821*/822if (cs35l56->base.irq)823disable_irq(cs35l56->base.irq);824825return 0;826}827828static int cs35l56_hda_system_resume_early(struct device *dev)829{830struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);831832/* Ensure a spec-compliant RESET pulse. */833if (cs35l56->base.reset_gpio) {834gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);835cs35l56_wait_min_reset_pulse();836837/* Release shared RESET before drivers start resume(). */838gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);839cs35l56_wait_control_port_ready();840}841842return 0;843}844845static int cs35l56_hda_system_resume(struct device *dev)846{847struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);848int ret;849850/* Undo pm_runtime_force_suspend() before re-enabling the irq */851ret = pm_runtime_force_resume(dev);852if (cs35l56->base.irq)853enable_irq(cs35l56->base.irq);854855if (ret)856return ret;857858cs35l56->suspended = false;859860if (!cs35l56->codec)861return 0;862863ret = cs35l56_is_fw_reload_needed(&cs35l56->base);864dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);865if (ret > 0)866queue_work(system_long_wq, &cs35l56->dsp_work);867868if (cs35l56->playing)869cs35l56_hda_play(cs35l56);870871return 0;872}873874static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)875{876/* The cirrus,dev-index property has the wrong values */877switch (*bus_addr) {878case 0x30:879cs35l56->index = 1;880return 0;881case 0x31:882cs35l56->index = 0;883return 0;884default:885/* There is a pseudo-address for broadcast to both amps - ignore it */886dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr);887return 0;888}889}890891static const struct {892const char *sub;893int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr);894} cs35l56_hda_fixups[] = {895{896.sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */897.fixup_fn = cs35l56_hda_fixup_yoga9,898},899};900901static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub,902int *bus_addr)903{904int i;905906if (IS_ERR(sub))907return 0;908909for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) {910if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) {911dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n",912cs35l56_hda_fixups[i].sub);913return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr);914}915}916917return 0;918}919920static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)921{922u32 values[HDA_MAX_COMPONENTS];923char hid_string[8];924struct acpi_device *adev;925const char *property, *sub;926size_t nval;927int i, ret;928929/*930* ACPI_COMPANION isn't available when this driver was instantiated by931* the serial-multi-instantiate driver, so lookup the node by HID932*/933if (!ACPI_COMPANION(cs35l56->base.dev)) {934snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);935adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);936if (!adev) {937dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",938dev_name(cs35l56->base.dev));939return -ENODEV;940}941ACPI_COMPANION_SET(cs35l56->base.dev, adev);942}943944/* Initialize things that could be overwritten by a fixup */945cs35l56->index = -1;946947sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));948ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id);949if (ret)950return ret;951952if (cs35l56->index == -1) {953property = "cirrus,dev-index";954ret = device_property_count_u32(cs35l56->base.dev, property);955if (ret <= 0)956goto err;957958if (ret > ARRAY_SIZE(values)) {959ret = -EINVAL;960goto err;961}962nval = ret;963964ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);965if (ret)966goto err;967968for (i = 0; i < nval; i++) {969if (values[i] == id) {970cs35l56->index = i;971break;972}973}974975/*976* It's not an error for the ID to be missing: for I2C there can be977* an alias address that is not a real device. So reject silently.978*/979if (cs35l56->index == -1) {980dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);981ret = -ENODEV;982goto err;983}984}985986if (IS_ERR(sub)) {987dev_info(cs35l56->base.dev,988"Read ACPI _SUB failed(%ld): fallback to generic firmware\n",989PTR_ERR(sub));990} else {991ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);992if (ret == -ENOENT) {993cs35l56->system_name = sub;994} else if (ret >= 0) {995cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);996kfree(sub);997if (!cs35l56->system_name)998return -ENOMEM;999} else {1000return ret;1001}1002}10031004cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,1005"reset",1006cs35l56->index,1007GPIOD_OUT_LOW);1008if (IS_ERR(cs35l56->base.reset_gpio)) {1009ret = PTR_ERR(cs35l56->base.reset_gpio);10101011/*1012* If RESET is shared the first amp to probe will grab the reset1013* line and reset all the amps1014*/1015if (ret != -EBUSY)1016return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");10171018dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");1019cs35l56->base.reset_gpio = NULL;1020}10211022return 0;10231024err:1025if (ret != -ENODEV)1026dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);10271028return ret;1029}10301031int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)1032{1033int ret;10341035mutex_init(&cs35l56->base.irq_lock);1036dev_set_drvdata(cs35l56->base.dev, cs35l56);10371038INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);10391040ret = cs35l56_hda_read_acpi(cs35l56, hid, id);1041if (ret)1042goto err;10431044cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",1045cs35l56->index + 1);1046if (!cs35l56->amp_name) {1047ret = -ENOMEM;1048goto err;1049}10501051cs35l56->base.cal_index = -1;10521053cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);1054cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;10551056if (cs35l56->base.reset_gpio) {1057dev_dbg(cs35l56->base.dev, "Hard reset\n");10581059/*1060* The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the1061* ACPI defines a different default state. So explicitly set low.1062*/1063gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);1064cs35l56_wait_min_reset_pulse();1065gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);1066}10671068ret = cs35l56_hw_init(&cs35l56->base);1069if (ret < 0)1070goto err;10711072/* Reset the device and wait for it to boot */1073cs35l56_system_reset(&cs35l56->base, false);1074ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);1075if (ret)1076goto err;10771078regcache_cache_only(cs35l56->base.regmap, false);10791080ret = cs35l56_set_patch(&cs35l56->base);1081if (ret)1082goto err;10831084regcache_mark_dirty(cs35l56->base.regmap);1085regcache_sync(cs35l56->base.regmap);10861087/* Disable auto-hibernate so that runtime_pm has control */1088ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);1089if (ret)1090goto err;10911092ret = cs35l56_get_calibration(&cs35l56->base);1093if (ret)1094goto err;10951096ret = cs_dsp_halo_init(&cs35l56->cs_dsp);1097if (ret) {1098dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");1099goto err;1100}11011102dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",1103cs35l56->system_name, cs35l56->amp_name);11041105regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,1106ARRAY_SIZE(cs35l56_hda_dai_config));11071108/*1109* By default only enable one ASP1TXn, where n=amplifier index,1110* This prevents multiple amps trying to drive the same slot.1111*/1112cs35l56->asp_tx_mask = BIT(cs35l56->index);11131114pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);1115pm_runtime_use_autosuspend(cs35l56->base.dev);1116pm_runtime_set_active(cs35l56->base.dev);1117pm_runtime_mark_last_busy(cs35l56->base.dev);1118pm_runtime_enable(cs35l56->base.dev);11191120cs35l56->base.init_done = true;11211122ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);1123if (ret) {1124dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);1125goto pm_err;1126}11271128return 0;11291130pm_err:1131pm_runtime_disable(cs35l56->base.dev);1132cs_dsp_remove(&cs35l56->cs_dsp);1133err:1134gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);11351136return ret;1137}1138EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56");11391140void cs35l56_hda_remove(struct device *dev)1141{1142struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);11431144component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);11451146pm_runtime_dont_use_autosuspend(cs35l56->base.dev);1147pm_runtime_get_sync(cs35l56->base.dev);1148pm_runtime_disable(cs35l56->base.dev);11491150cs_dsp_remove(&cs35l56->cs_dsp);11511152kfree(cs35l56->system_name);1153pm_runtime_put_noidle(cs35l56->base.dev);11541155gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);1156}1157EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56");11581159const struct dev_pm_ops cs35l56_hda_pm_ops = {1160RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)1161SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)1162LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,1163cs35l56_hda_system_resume_early)1164NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,1165cs35l56_hda_system_resume_no_irq)1166};1167EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56");11681169MODULE_DESCRIPTION("CS35L56 HDA Driver");1170MODULE_IMPORT_NS("FW_CS_DSP");1171MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");1172MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");1173MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");1174MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");1175MODULE_AUTHOR("Simon Trimmer <[email protected]>");1176MODULE_LICENSE("GPL");1177MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw");1178MODULE_FIRMWARE("cirrus/cs35l54-*.bin");1179MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw");1180MODULE_FIRMWARE("cirrus/cs35l56-*.bin");118111821183