Path: blob/master/sound/hda/codecs/side-codecs/cs35l56_hda.c
51323 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 int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)551{552int ret;553554if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)555return -EACCES;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);562return ret;563}564565dev_info(cs35l56->base.dev, "Calibration applied\n");566567return 0;568}569570static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)571{572const struct firmware *coeff_firmware = NULL;573const struct firmware *wmfw_firmware = NULL;574char *coeff_filename = NULL;575char *wmfw_filename = NULL;576unsigned int preloaded_fw_ver;577bool firmware_missing;578int ret;579580/*581* Prepare for a new DSP power-up. If the DSP has had firmware582* downloaded previously then it needs to be powered down so that it583* can be updated.584*/585if (cs35l56->base.fw_patched)586cs_dsp_power_down(&cs35l56->cs_dsp);587588cs35l56->base.fw_patched = false;589590PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56->base.dev, pm);591ret = PM_RUNTIME_ACQUIRE_ERR(&pm);592if (ret < 0) {593dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);594return;595}596597/*598* The firmware can only be upgraded if it is currently running599* from the built-in ROM. If not, the wmfw/bin must be for the600* version of firmware that is running on the chip.601*/602ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);603if (ret)604return;605606if (firmware_missing)607preloaded_fw_ver = 0;608609cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,610&wmfw_firmware, &wmfw_filename,611&coeff_firmware, &coeff_filename);612613/*614* If the BIOS didn't patch the firmware a bin file is mandatory to615* enable the ASPĀ·616*/617if (!coeff_firmware && firmware_missing) {618dev_err(cs35l56->base.dev, ".bin file required but not found\n");619goto err_fw_release;620}621622mutex_lock(&cs35l56->base.irq_lock);623624/*625* If the firmware hasn't been patched it must be shutdown before626* doing a full patch and reset afterwards. If it is already627* running a patched version the firmware files only contain628* tunings and we can use the lower cost reinit sequence instead.629*/630if (firmware_missing && (wmfw_firmware || coeff_firmware)) {631ret = cs35l56_firmware_shutdown(&cs35l56->base);632if (ret)633goto err;634}635636ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,637coeff_firmware, coeff_filename, "misc");638if (ret) {639dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);640goto err;641}642643if (wmfw_filename)644dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);645646if (coeff_filename)647dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);648649/* If we downloaded firmware, reset the device and wait for it to boot */650if (firmware_missing && (wmfw_firmware || coeff_firmware)) {651cs35l56_system_reset(&cs35l56->base, false);652regcache_mark_dirty(cs35l56->base.regmap);653ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);654if (ret)655goto err_powered_up;656657regcache_cache_only(cs35l56->base.regmap, false);658}659660/* Disable auto-hibernate so that runtime_pm has control */661ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);662if (ret)663goto err_powered_up;664665regcache_sync(cs35l56->base.regmap);666667regmap_clear_bits(cs35l56->base.regmap,668cs35l56->base.fw_reg->prot_sts,669CS35L56_FIRMWARE_MISSING);670cs35l56->base.fw_patched = true;671672ret = cs_dsp_run(&cs35l56->cs_dsp);673if (ret)674dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);675676/* Don't need to check return code, it's not fatal if this fails */677cs35l56_hda_apply_calibration(cs35l56);678679ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);680if (ret)681cs_dsp_stop(&cs35l56->cs_dsp);682683cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp);684685err_powered_up:686if (!cs35l56->base.fw_patched)687cs_dsp_power_down(&cs35l56->cs_dsp);688err:689mutex_unlock(&cs35l56->base.irq_lock);690err_fw_release:691cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,692coeff_firmware, coeff_filename);693}694695static void cs35l56_hda_dsp_work(struct work_struct *work)696{697struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);698699cs35l56_hda_fw_load(cs35l56);700}701702static ssize_t cs35l56_hda_debugfs_calibrate_write(struct file *file,703const char __user *from,704size_t count, loff_t *ppos)705{706struct cs35l56_base *cs35l56_base = file->private_data;707ssize_t ret;708709PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(cs35l56_base->dev, pm);710ret = PM_RUNTIME_ACQUIRE_ERR(&pm);711if (ret)712return ret;713714return cs35l56_calibrate_debugfs_write(cs35l56_base, from, count, ppos);715}716717static ssize_t cs35l56_hda_debugfs_cal_temperature_write(struct file *file,718const char __user *from,719size_t count, loff_t *ppos)720{721struct cs35l56_base *cs35l56_base = file->private_data;722ssize_t ret;723724PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(cs35l56_base->dev, pm);725ret = PM_RUNTIME_ACQUIRE_ERR(&pm);726if (ret)727return ret;728729return cs35l56_cal_ambient_debugfs_write(cs35l56_base, from, count, ppos);730}731732static ssize_t cs35l56_hda_debugfs_cal_data_read(struct file *file,733char __user *to,734size_t count, loff_t *ppos)735{736struct cs35l56_base *cs35l56_base = file->private_data;737ssize_t ret;738739PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(cs35l56_base->dev, pm);740ret = PM_RUNTIME_ACQUIRE_ERR(&pm);741if (ret)742return ret;743744return cs35l56_cal_data_debugfs_read(cs35l56_base, to, count, ppos);745}746747static ssize_t cs35l56_hda_debugfs_cal_data_write(struct file *file,748const char __user *from,749size_t count, loff_t *ppos)750{751struct cs35l56_base *cs35l56_base = file->private_data;752struct cs35l56_hda *cs35l56 = cs35l56_hda_from_base(cs35l56_base);753ssize_t ret;754755ret = cs35l56_cal_data_debugfs_write(cs35l56_base, from, count, ppos);756if (ret == -ENODATA)757return count; /* Ignore writes of empty cal blobs */758759if (ret < 0)760return ret;761762PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(cs35l56_base->dev, pm);763ret = PM_RUNTIME_ACQUIRE_ERR(&pm);764if (ret)765return ret;766767ret = cs35l56_hda_apply_calibration(cs35l56);768if (ret == 0)769cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_AUDIO_REINIT);770else771count = -EIO;772773return count;774}775776static const struct cs35l56_cal_debugfs_fops cs35l56_hda_cal_debugfs_fops = {777.calibrate = {778.write = cs35l56_hda_debugfs_calibrate_write,779},780.cal_temperature = {781.write = cs35l56_hda_debugfs_cal_temperature_write,782},783.cal_data = {784.read = cs35l56_hda_debugfs_cal_data_read,785.write = cs35l56_hda_debugfs_cal_data_write,786},787};788789static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)790{791struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);792struct hda_component_parent *parent = master_data;793struct hda_component *comp;794795comp = hda_component_from_index(parent, cs35l56->index);796if (!comp)797return -EINVAL;798799if (comp->dev)800return -EBUSY;801802comp->dev = dev;803cs35l56->codec = parent->codec;804strscpy(comp->name, dev_name(dev), sizeof(comp->name));805comp->playback_hook = cs35l56_hda_playback_hook;806807queue_work(system_long_wq, &cs35l56->dsp_work);808809cs35l56_hda_create_controls(cs35l56);810811#if IS_ENABLED(CONFIG_SND_DEBUG)812cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);813cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);814#endif815816if (IS_ENABLED(CONFIG_SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS))817cs35l56_create_cal_debugfs(&cs35l56->base, &cs35l56_hda_cal_debugfs_fops);818819dev_dbg(cs35l56->base.dev, "Bound\n");820821return 0;822}823824static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)825{826struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);827struct hda_component_parent *parent = master_data;828struct hda_component *comp;829830cancel_work_sync(&cs35l56->dsp_work);831832cs35l56_remove_cal_debugfs(&cs35l56->base);833cs35l56_hda_remove_controls(cs35l56);834835#if IS_ENABLED(CONFIG_SND_DEBUG)836cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);837debugfs_remove_recursive(cs35l56->debugfs_root);838#endif839840if (cs35l56->base.fw_patched)841cs_dsp_power_down(&cs35l56->cs_dsp);842843comp = hda_component_from_index(parent, cs35l56->index);844if (comp && (comp->dev == dev))845memset(comp, 0, sizeof(*comp));846847cs35l56->codec = NULL;848849dev_dbg(cs35l56->base.dev, "Unbound\n");850}851852static const struct component_ops cs35l56_hda_comp_ops = {853.bind = cs35l56_hda_bind,854.unbind = cs35l56_hda_unbind,855};856857static int cs35l56_hda_system_suspend(struct device *dev)858{859struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);860861cs35l56_hda_wait_dsp_ready(cs35l56);862863if (cs35l56->playing)864cs35l56_hda_pause(cs35l56);865866cs35l56->suspended = true;867868/*869* The interrupt line is normally shared, but after we start suspending870* we can't check if our device is the source of an interrupt, and can't871* clear it. Prevent this race by temporarily disabling the parent irq872* until we reach _no_irq.873*/874if (cs35l56->base.irq)875disable_irq(cs35l56->base.irq);876877return pm_runtime_force_suspend(dev);878}879880static int cs35l56_hda_system_suspend_late(struct device *dev)881{882struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);883884/*885* RESET is usually shared by all amps so it must not be asserted until886* all driver instances have done their suspend() stage.887*/888if (cs35l56->base.reset_gpio) {889gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);890cs35l56_wait_min_reset_pulse();891}892893return 0;894}895896static int cs35l56_hda_system_suspend_no_irq(struct device *dev)897{898struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);899900/* Handlers are now disabled so the parent IRQ can safely be re-enabled. */901if (cs35l56->base.irq)902enable_irq(cs35l56->base.irq);903904return 0;905}906907static int cs35l56_hda_system_resume_no_irq(struct device *dev)908{909struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);910911/*912* WAKE interrupts unmask if the CS35L56 hibernates, which can cause913* spurious interrupts, and the interrupt line is normally shared.914* We can't check if our device is the source of an interrupt, and can't915* clear it, until it has fully resumed. Prevent this race by temporarily916* disabling the parent irq until we complete resume().917*/918if (cs35l56->base.irq)919disable_irq(cs35l56->base.irq);920921return 0;922}923924static int cs35l56_hda_system_resume_early(struct device *dev)925{926struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);927928/* Ensure a spec-compliant RESET pulse. */929if (cs35l56->base.reset_gpio) {930gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);931cs35l56_wait_min_reset_pulse();932933/* Release shared RESET before drivers start resume(). */934gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);935cs35l56_wait_control_port_ready();936}937938return 0;939}940941static int cs35l56_hda_system_resume(struct device *dev)942{943struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);944int ret;945946/* Undo pm_runtime_force_suspend() before re-enabling the irq */947ret = pm_runtime_force_resume(dev);948if (cs35l56->base.irq)949enable_irq(cs35l56->base.irq);950951if (ret)952return ret;953954cs35l56->suspended = false;955956if (!cs35l56->codec)957return 0;958959ret = cs35l56_is_fw_reload_needed(&cs35l56->base);960dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);961if (ret > 0)962queue_work(system_long_wq, &cs35l56->dsp_work);963964if (cs35l56->playing)965cs35l56_hda_play(cs35l56);966967return 0;968}969970static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)971{972/* The cirrus,dev-index property has the wrong values */973switch (*bus_addr) {974case 0x30:975cs35l56->index = 1;976return 0;977case 0x31:978cs35l56->index = 0;979return 0;980default:981/* There is a pseudo-address for broadcast to both amps - ignore it */982dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr);983return 0;984}985}986987static const struct {988const char *sub;989int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr);990} cs35l56_hda_fixups[] = {991{992.sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */993.fixup_fn = cs35l56_hda_fixup_yoga9,994},995};996997static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub,998int *bus_addr)999{1000int i;10011002if (IS_ERR(sub))1003return 0;10041005for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) {1006if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) {1007dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n",1008cs35l56_hda_fixups[i].sub);1009return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr);1010}1011}10121013return 0;1014}10151016static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)1017{1018u32 values[HDA_MAX_COMPONENTS];1019char hid_string[8];1020struct acpi_device *adev;1021const char *property, *sub;1022size_t nval;1023int i, ret;10241025/*1026* ACPI_COMPANION isn't available when this driver was instantiated by1027* the serial-multi-instantiate driver, so lookup the node by HID1028*/1029if (!ACPI_COMPANION(cs35l56->base.dev)) {1030snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);1031adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);1032if (!adev) {1033dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",1034dev_name(cs35l56->base.dev));1035return -ENODEV;1036}1037ACPI_COMPANION_SET(cs35l56->base.dev, adev);1038}10391040/* Initialize things that could be overwritten by a fixup */1041cs35l56->index = -1;10421043sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));1044ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id);1045if (ret)1046return ret;10471048if (cs35l56->index == -1) {1049property = "cirrus,dev-index";1050ret = device_property_count_u32(cs35l56->base.dev, property);1051if (ret <= 0)1052goto err;10531054if (ret > ARRAY_SIZE(values)) {1055ret = -EINVAL;1056goto err;1057}1058nval = ret;10591060ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);1061if (ret)1062goto err;10631064for (i = 0; i < nval; i++) {1065if (values[i] == id) {1066cs35l56->index = i;1067break;1068}1069}10701071/*1072* It's not an error for the ID to be missing: for I2C there can be1073* an alias address that is not a real device. So reject silently.1074*/1075if (cs35l56->index == -1) {1076dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);1077ret = -ENODEV;1078goto err;1079}1080}10811082if (IS_ERR(sub)) {1083dev_info(cs35l56->base.dev,1084"Read ACPI _SUB failed(%ld): fallback to generic firmware\n",1085PTR_ERR(sub));1086} else {1087ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);1088if (ret == -ENOENT) {1089cs35l56->system_name = sub;1090} else if (ret >= 0) {1091cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);1092kfree(sub);1093if (!cs35l56->system_name)1094return -ENOMEM;1095} else {1096return ret;1097}1098}10991100cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,1101"reset",1102cs35l56->index,1103GPIOD_OUT_LOW);1104if (IS_ERR(cs35l56->base.reset_gpio)) {1105ret = PTR_ERR(cs35l56->base.reset_gpio);11061107/*1108* If RESET is shared the first amp to probe will grab the reset1109* line and reset all the amps1110*/1111if (ret != -EBUSY)1112return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");11131114dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");1115cs35l56->base.reset_gpio = NULL;1116}11171118return 0;11191120err:1121if (ret != -ENODEV)1122dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);11231124return ret;1125}11261127int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)1128{1129int ret;11301131mutex_init(&cs35l56->base.irq_lock);1132dev_set_drvdata(cs35l56->base.dev, cs35l56);11331134INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);11351136ret = cs35l56_hda_read_acpi(cs35l56, hid, id);1137if (ret)1138goto err;11391140cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",1141cs35l56->index + 1);1142if (!cs35l56->amp_name) {1143ret = -ENOMEM;1144goto err;1145}11461147cs35l56->base.type = hid & 0xff;1148cs35l56->base.cal_index = cs35l56->index;11491150cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);1151cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;11521153if (cs35l56->base.reset_gpio) {1154dev_dbg(cs35l56->base.dev, "Hard reset\n");11551156/*1157* The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the1158* ACPI defines a different default state. So explicitly set low.1159*/1160gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);1161cs35l56_wait_min_reset_pulse();1162gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);1163}11641165ret = cs35l56_hw_init(&cs35l56->base);1166if (ret < 0)1167goto err;11681169/* Reset the device and wait for it to boot */1170cs35l56_system_reset(&cs35l56->base, false);1171ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);1172if (ret)1173goto err;11741175regcache_cache_only(cs35l56->base.regmap, false);11761177ret = cs35l56_set_patch(&cs35l56->base);1178if (ret)1179goto err;11801181regcache_mark_dirty(cs35l56->base.regmap);1182regcache_sync(cs35l56->base.regmap);11831184/* Disable auto-hibernate so that runtime_pm has control */1185ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);1186if (ret)1187goto err;11881189ret = cs35l56_get_calibration(&cs35l56->base);1190if (ret)1191goto err;11921193ret = cs_dsp_halo_init(&cs35l56->cs_dsp);1194if (ret) {1195dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");1196goto err;1197}11981199dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",1200cs35l56->system_name, cs35l56->amp_name);12011202regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,1203ARRAY_SIZE(cs35l56_hda_dai_config));12041205/*1206* By default only enable one ASP1TXn, where n=amplifier index,1207* This prevents multiple amps trying to drive the same slot.1208*/1209cs35l56->asp_tx_mask = BIT(cs35l56->index);12101211pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);1212pm_runtime_use_autosuspend(cs35l56->base.dev);1213pm_runtime_set_active(cs35l56->base.dev);1214pm_runtime_mark_last_busy(cs35l56->base.dev);1215pm_runtime_enable(cs35l56->base.dev);12161217cs35l56->base.init_done = true;12181219ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);1220if (ret) {1221dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);1222goto pm_err;1223}12241225return 0;12261227pm_err:1228pm_runtime_disable(cs35l56->base.dev);1229cs_dsp_remove(&cs35l56->cs_dsp);1230err:1231gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);12321233return ret;1234}1235EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56");12361237void cs35l56_hda_remove(struct device *dev)1238{1239struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);12401241component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);12421243pm_runtime_dont_use_autosuspend(cs35l56->base.dev);1244pm_runtime_get_sync(cs35l56->base.dev);1245pm_runtime_disable(cs35l56->base.dev);12461247cs_dsp_remove(&cs35l56->cs_dsp);12481249kfree(cs35l56->system_name);1250pm_runtime_put_noidle(cs35l56->base.dev);12511252gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);1253}1254EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56");12551256const struct dev_pm_ops cs35l56_hda_pm_ops = {1257RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)1258SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)1259LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,1260cs35l56_hda_system_resume_early)1261NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,1262cs35l56_hda_system_resume_no_irq)1263};1264EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56");12651266MODULE_DESCRIPTION("CS35L56 HDA Driver");1267MODULE_IMPORT_NS("FW_CS_DSP");1268MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");1269MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");1270MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");1271MODULE_AUTHOR("Richard Fitzgerald <[email protected]>");1272MODULE_AUTHOR("Simon Trimmer <[email protected]>");1273MODULE_LICENSE("GPL");1274MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw");1275MODULE_FIRMWARE("cirrus/cs35l54-*.bin");1276MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw");1277MODULE_FIRMWARE("cirrus/cs35l56-*.bin");127812791280