Path: blob/master/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
26481 views
// SPDX-License-Identifier: GPL-2.01//2// TAS2781 HDA I2C driver3//4// Copyright 2023 - 2025 Texas Instruments, Inc.5//6// Author: Shenghao Ding <[email protected]>7// Current maintainer: Baojun Xu <[email protected]>89#include <linux/unaligned.h>10#include <linux/acpi.h>11#include <linux/crc8.h>12#include <linux/crc32.h>13#include <linux/efi.h>14#include <linux/firmware.h>15#include <linux/i2c.h>16#include <linux/mod_devicetable.h>17#include <linux/module.h>18#include <linux/pci_ids.h>19#include <linux/pm_runtime.h>20#include <linux/regmap.h>21#include <sound/hda_codec.h>22#include <sound/soc.h>23#include <sound/tas2781.h>24#include <sound/tas2781-comlib-i2c.h>25#include <sound/tlv.h>26#include <sound/tas2770-tlv.h>27#include <sound/tas2781-tlv.h>2829#include "hda_local.h"30#include "hda_auto_parser.h"31#include "hda_component.h"32#include "hda_jack.h"33#include "../generic.h"34#include "tas2781_hda.h"3536#define TAS2563_CAL_VAR_NAME_MAX 1637#define TAS2563_CAL_ARRAY_SIZE 8038#define TAS2563_CAL_DATA_SIZE 439#define TAS2563_MAX_CHANNELS 440#define TAS2563_CAL_CH_SIZE 204142#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48)43#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c)44#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40)45#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14)46#define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34)4748enum device_chip_id {49HDA_TAS2563,50HDA_TAS2770,51HDA_TAS2781,52HDA_OTHERS53};5455struct tas2781_hda_i2c_priv {56struct snd_kcontrol *snd_ctls[2];57int (*save_calibration)(struct tas2781_hda *h);5859int hda_chip_id;60};6162static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)63{64struct tasdevice_priv *tas_priv = data;65struct acpi_resource_i2c_serialbus *sb;6667if (i2c_acpi_get_i2c_resource(ares, &sb)) {68if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS &&69sb->slave_address != tas_priv->global_addr) {70tas_priv->tasdevice[tas_priv->ndev].dev_addr =71(unsigned int)sb->slave_address;72tas_priv->ndev++;73}74}75return 1;76}7778static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };7980static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {81{ "speakerid-gpios", &speakerid_gpios, 1 },82{ }83};8485static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)86{87struct acpi_device *adev;88struct device *physdev;89LIST_HEAD(resources);90const char *sub;91uint32_t subid;92int ret;9394adev = acpi_dev_get_first_match_dev(hid, NULL, -1);95if (!adev) {96dev_err(p->dev,97"Failed to find an ACPI device for %s\n", hid);98return -ENODEV;99}100101physdev = get_device(acpi_get_first_physical_node(adev));102ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);103if (ret < 0) {104dev_err(p->dev, "Failed to get ACPI resource.\n");105goto err;106}107sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));108if (IS_ERR(sub)) {109/* No subsys id in older tas2563 projects. */110if (!strncmp(hid, "INT8866", sizeof("INT8866")))111goto end_2563;112dev_err(p->dev, "Failed to get SUBSYS ID.\n");113ret = PTR_ERR(sub);114goto err;115}116/* Speaker id was needed for ASUS projects. */117ret = kstrtou32(sub, 16, &subid);118if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {119ret = devm_acpi_dev_add_driver_gpios(p->dev,120tas2781_speaker_id_gpios);121if (ret < 0)122dev_err(p->dev, "Failed to add driver gpio %d.\n",123ret);124p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);125if (IS_ERR(p->speaker_id)) {126dev_err(p->dev, "Failed to get Speaker id.\n");127ret = PTR_ERR(p->speaker_id);128goto err;129}130} else {131p->speaker_id = NULL;132}133134end_2563:135acpi_dev_free_resource_list(&resources);136strscpy(p->dev_name, hid, sizeof(p->dev_name));137put_device(physdev);138acpi_dev_put(adev);139140return 0;141142err:143dev_err(p->dev, "read acpi error, ret: %d\n", ret);144put_device(physdev);145acpi_dev_put(adev);146147return ret;148}149150static void tas2781_hda_playback_hook(struct device *dev, int action)151{152struct tas2781_hda *tas_hda = dev_get_drvdata(dev);153154dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action);155switch (action) {156case HDA_GEN_PCM_ACT_OPEN:157pm_runtime_get_sync(dev);158mutex_lock(&tas_hda->priv->codec_lock);159tasdevice_tuning_switch(tas_hda->priv, 0);160tas_hda->priv->playback_started = true;161mutex_unlock(&tas_hda->priv->codec_lock);162break;163case HDA_GEN_PCM_ACT_CLOSE:164mutex_lock(&tas_hda->priv->codec_lock);165tasdevice_tuning_switch(tas_hda->priv, 1);166tas_hda->priv->playback_started = false;167mutex_unlock(&tas_hda->priv->codec_lock);168169pm_runtime_put_autosuspend(dev);170break;171default:172break;173}174}175176static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,177struct snd_ctl_elem_value *ucontrol)178{179struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);180struct soc_mixer_control *mc =181(struct soc_mixer_control *)kcontrol->private_value;182int ret;183184mutex_lock(&tas_priv->codec_lock);185186ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);187188dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",189__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);190191mutex_unlock(&tas_priv->codec_lock);192193return ret;194}195196static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,197struct snd_ctl_elem_value *ucontrol)198{199struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);200struct soc_mixer_control *mc =201(struct soc_mixer_control *)kcontrol->private_value;202int ret;203204mutex_lock(&tas_priv->codec_lock);205206dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",207__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);208209/* The check of the given value is in tasdevice_amp_putvol. */210ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);211212mutex_unlock(&tas_priv->codec_lock);213214return ret;215}216217static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,218struct snd_ctl_elem_value *ucontrol)219{220struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);221222mutex_lock(&tas_priv->codec_lock);223224ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;225dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",226__func__, kcontrol->id.name, tas_priv->force_fwload_status);227228mutex_unlock(&tas_priv->codec_lock);229230return 0;231}232233static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,234struct snd_ctl_elem_value *ucontrol)235{236struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);237bool change, val = (bool)ucontrol->value.integer.value[0];238239mutex_lock(&tas_priv->codec_lock);240241dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",242__func__, kcontrol->id.name,243tas_priv->force_fwload_status, val);244245if (tas_priv->force_fwload_status == val)246change = false;247else {248change = true;249tas_priv->force_fwload_status = val;250}251252mutex_unlock(&tas_priv->codec_lock);253254return change;255}256257static const struct snd_kcontrol_new tas2770_snd_controls[] = {258ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2770_AMP_LEVEL,2590, 0, 20, 0, tas2781_amp_getvol,260tas2781_amp_putvol, tas2770_amp_tlv),261ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2770_DVC_LEVEL,2620, 0, 200, 1, tas2781_amp_getvol,263tas2781_amp_putvol, tas2770_dvc_tlv),264};265266static const struct snd_kcontrol_new tas2781_snd_controls[] = {267ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,2681, 0, 20, 0, tas2781_amp_getvol,269tas2781_amp_putvol, tas2781_amp_tlv),270ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,271tas2781_force_fwload_get, tas2781_force_fwload_put),272};273274static const struct snd_kcontrol_new tasdevice_prof_ctrl = {275.name = "Speaker Profile Id",276.iface = SNDRV_CTL_ELEM_IFACE_CARD,277.info = tasdevice_info_profile,278.get = tasdevice_get_profile_id,279.put = tasdevice_set_profile_id,280};281282static const struct snd_kcontrol_new tasdevice_dsp_prog_ctrl = {283.name = "Speaker Program Id",284.iface = SNDRV_CTL_ELEM_IFACE_CARD,285.info = tasdevice_info_programs,286.get = tasdevice_program_get,287.put = tasdevice_program_put,288};289290static const struct snd_kcontrol_new tasdevice_dsp_conf_ctrl = {291.name = "Speaker Config Id",292.iface = SNDRV_CTL_ELEM_IFACE_CARD,293.info = tasdevice_info_config,294.get = tasdevice_config_get,295.put = tasdevice_config_put,296};297298static int tas2563_save_calibration(struct tas2781_hda *h)299{300efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];301char *vars[TASDEV_CALIB_N] = {302"R0_%d", "R0_Low_%d", "InvR0_%d", "Power_%d", "TLim_%d"303};304efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX];305unsigned long max_size = TAS2563_CAL_DATA_SIZE;306unsigned char var8[TAS2563_CAL_VAR_NAME_MAX];307struct tasdevice_priv *p = h->priv;308struct calidata *cd = &p->cali_data;309struct cali_reg *r = &cd->cali_reg_array;310unsigned int offset = 0;311unsigned char *data;312__be32 bedata;313efi_status_t status;314unsigned int attr;315int ret, i, j, k;316317cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N;318319/* extra byte for each device is the device number */320cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev;321data = cd->data = devm_kzalloc(p->dev, cd->total_sz,322GFP_KERNEL);323if (!data)324return -ENOMEM;325326for (i = 0; i < p->ndev; ++i) {327data[offset] = i;328offset++;329for (j = 0; j < TASDEV_CALIB_N; ++j) {330/* EFI name for calibration started with 1, not 0 */331ret = snprintf(var8, sizeof(var8), vars[j], i + 1);332if (ret < 0 || ret >= sizeof(var8) - 1) {333dev_err(p->dev, "%s: Read %s failed\n",334__func__, var8);335return -EINVAL;336}337/*338* Our variable names are ASCII by construction, but339* EFI names are wide chars. Convert and zero-pad.340*/341memset(efi_name, 0, sizeof(efi_name));342for (k = 0; k < sizeof(var8) && var8[k]; k++)343efi_name[k] = var8[k];344status = efi.get_variable(efi_name,345&efi_guid, &attr, &max_size,346&data[offset]);347if (status != EFI_SUCCESS ||348max_size != TAS2563_CAL_DATA_SIZE) {349dev_warn(p->dev,350"Dev %d: Caldat[%d] read failed %ld\n",351i, j, status);352return -EINVAL;353}354bedata = cpu_to_be32(*(uint32_t *)&data[offset]);355memcpy(&data[offset], &bedata, sizeof(bedata));356offset += TAS2563_CAL_DATA_SIZE;357}358}359360if (cd->total_sz != offset) {361dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n",362__func__, cd->total_sz, offset);363return -EINVAL;364}365366r->r0_reg = TAS2563_CAL_R0;367r->invr0_reg = TAS2563_CAL_INVR0;368r->r0_low_reg = TAS2563_CAL_R0_LOW;369r->pow_reg = TAS2563_CAL_POWER;370r->tlimit_reg = TAS2563_CAL_TLIM;371372/*373* TAS2781_FMWLIB supports two solutions of calibrated data. One is374* from the driver itself: driver reads the calibrated files directly375* during probe; The other from user space: during init of audio hal,376* the audio hal will pass the calibrated data via kcontrol interface.377* Driver will store this data in "struct calidata" for use. For hda378* device, calibrated data are usunally saved into UEFI. So Hda side379* codec driver use the mixture of these two solutions, driver reads380* the data from UEFI, then store this data in "struct calidata" for381* use.382*/383p->is_user_space_calidata = true;384385return 0;386}387388static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)389{390struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;391struct hda_codec *codec = tas_hda->priv->codec;392393snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);394snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);395396for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--)397snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);398399snd_ctl_remove(codec->card, tas_hda->prof_ctl);400}401402static void tasdev_add_kcontrols(struct tasdevice_priv *tas_priv,403struct snd_kcontrol **ctls, struct hda_codec *codec,404const struct snd_kcontrol_new *tas_snd_ctrls, int num_ctls)405{406int i, ret;407408for (i = 0; i < num_ctls; i++) {409ctls[i] = snd_ctl_new1(410&tas_snd_ctrls[i], tas_priv);411ret = snd_ctl_add(codec->card, ctls[i]);412if (ret) {413dev_err(tas_priv->dev,414"Failed to add KControl %s = %d\n",415tas_snd_ctrls[i].name, ret);416break;417}418}419}420421static void tasdevice_dspfw_init(void *context)422{423struct tasdevice_priv *tas_priv = context;424struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);425struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;426struct hda_codec *codec = tas_priv->codec;427int ret, spk_id;428429tasdevice_dsp_remove(tas_priv);430tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;431if (tas_priv->speaker_id != NULL) {432// Speaker id need to be checked for ASUS only.433spk_id = gpiod_get_value(tas_priv->speaker_id);434if (spk_id < 0) {435// Speaker id is not valid, use default.436dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);437spk_id = 0;438}439snprintf(tas_priv->coef_binaryname,440sizeof(tas_priv->coef_binaryname),441"TAS2XXX%04X%d.bin",442lower_16_bits(codec->core.subsystem_id),443spk_id);444} else {445snprintf(tas_priv->coef_binaryname,446sizeof(tas_priv->coef_binaryname),447"TAS2XXX%04X.bin",448lower_16_bits(codec->core.subsystem_id));449}450ret = tasdevice_dsp_parser(tas_priv);451if (ret) {452dev_err(tas_priv->dev, "dspfw load %s error\n",453tas_priv->coef_binaryname);454tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;455return;456}457tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_prog_ctl, codec,458&tasdevice_dsp_prog_ctrl, 1);459tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_conf_ctl, codec,460&tasdevice_dsp_conf_ctrl, 1);461462tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;463tasdevice_prmg_load(tas_priv, 0);464if (tas_priv->fmw->nr_programs > 0)465tas_priv->cur_prog = 0;466if (tas_priv->fmw->nr_configurations > 0)467tas_priv->cur_conf = 0;468469/* If calibrated data occurs error, dsp will still works with default470* calibrated data inside algo.471*/472hda_priv->save_calibration(tas_hda);473}474475static void tasdev_fw_ready(const struct firmware *fmw, void *context)476{477struct tasdevice_priv *tas_priv = context;478struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);479struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;480struct hda_codec *codec = tas_priv->codec;481int ret;482483pm_runtime_get_sync(tas_priv->dev);484mutex_lock(&tas_priv->codec_lock);485486ret = tasdevice_rca_parser(tas_priv, fmw);487if (ret)488goto out;489490tas_priv->fw_state = TASDEVICE_RCA_FW_OK;491tasdev_add_kcontrols(tas_priv, &tas_hda->prof_ctl, codec,492&tasdevice_prof_ctrl, 1);493494switch (hda_priv->hda_chip_id) {495case HDA_TAS2770:496tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,497&tas2770_snd_controls[0],498ARRAY_SIZE(tas2770_snd_controls));499break;500case HDA_TAS2781:501tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,502&tas2781_snd_controls[0],503ARRAY_SIZE(tas2781_snd_controls));504tasdevice_dspfw_init(context);505break;506case HDA_TAS2563:507tasdevice_dspfw_init(context);508break;509default:510break;511}512513out:514mutex_unlock(&tas_hda->priv->codec_lock);515release_firmware(fmw);516pm_runtime_put_autosuspend(tas_hda->dev);517}518519static int tas2781_hda_bind(struct device *dev, struct device *master,520void *master_data)521{522struct tas2781_hda *tas_hda = dev_get_drvdata(dev);523struct hda_component_parent *parent = master_data;524struct hda_component *comp;525struct hda_codec *codec;526unsigned int subid;527int ret;528529comp = hda_component_from_index(parent, tas_hda->priv->index);530if (!comp)531return -EINVAL;532533if (comp->dev)534return -EBUSY;535536codec = parent->codec;537subid = codec->core.subsystem_id >> 16;538539switch (subid) {540case 0x1028:541tas_hda->catlog_id = DELL;542break;543default:544tas_hda->catlog_id = LENOVO;545break;546}547548pm_runtime_get_sync(dev);549550comp->dev = dev;551552strscpy(comp->name, dev_name(dev), sizeof(comp->name));553554ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);555if (!ret)556comp->playback_hook = tas2781_hda_playback_hook;557558pm_runtime_put_autosuspend(dev);559560return ret;561}562563static void tas2781_hda_unbind(struct device *dev,564struct device *master, void *master_data)565{566struct tas2781_hda *tas_hda = dev_get_drvdata(dev);567struct hda_component_parent *parent = master_data;568struct hda_component *comp;569570comp = hda_component_from_index(parent, tas_hda->priv->index);571if (comp && (comp->dev == dev)) {572comp->dev = NULL;573memset(comp->name, 0, sizeof(comp->name));574comp->playback_hook = NULL;575}576577tas2781_hda_remove_controls(tas_hda);578579tasdevice_config_info_remove(tas_hda->priv);580tasdevice_dsp_remove(tas_hda->priv);581582tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;583}584585static const struct component_ops tas2781_hda_comp_ops = {586.bind = tas2781_hda_bind,587.unbind = tas2781_hda_unbind,588};589590static int tas2781_hda_i2c_probe(struct i2c_client *clt)591{592struct tas2781_hda_i2c_priv *hda_priv;593struct tas2781_hda *tas_hda;594const char *device_name;595int ret;596597tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);598if (!tas_hda)599return -ENOMEM;600601hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);602if (!hda_priv)603return -ENOMEM;604605tas_hda->hda_priv = hda_priv;606607dev_set_drvdata(&clt->dev, tas_hda);608tas_hda->dev = &clt->dev;609610tas_hda->priv = tasdevice_kzalloc(clt);611if (!tas_hda->priv)612return -ENOMEM;613614if (strstr(dev_name(&clt->dev), "TIAS2781")) {615/*616* TAS2781, integrated on-chip DSP with617* global I2C address supported.618*/619device_name = "TIAS2781";620hda_priv->hda_chip_id = HDA_TAS2781;621hda_priv->save_calibration = tas2781_save_calibration;622tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;623} else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) {624/*625* TAS2770, has no on-chip DSP, so no calibration data626* required; has no global I2C address supported.627*/628device_name = "TXNW2770";629hda_priv->hda_chip_id = HDA_TAS2770;630} else if (strstarts(dev_name(&clt->dev),631"i2c-TXNW2781:00-tas2781-hda.0")) {632device_name = "TXNW2781";633hda_priv->save_calibration = tas2781_save_calibration;634tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;635} else if (strstr(dev_name(&clt->dev), "INT8866")) {636/*637* TAS2563, integrated on-chip DSP with638* global I2C address supported.639*/640device_name = "INT8866";641hda_priv->hda_chip_id = HDA_TAS2563;642hda_priv->save_calibration = tas2563_save_calibration;643tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;644} else {645return -ENODEV;646}647648tas_hda->priv->irq = clt->irq;649ret = tas2781_read_acpi(tas_hda->priv, device_name);650if (ret)651return dev_err_probe(tas_hda->dev, ret,652"Platform not supported\n");653654ret = tasdevice_init(tas_hda->priv);655if (ret)656goto err;657658pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000);659pm_runtime_use_autosuspend(tas_hda->dev);660pm_runtime_mark_last_busy(tas_hda->dev);661pm_runtime_set_active(tas_hda->dev);662pm_runtime_enable(tas_hda->dev);663664tasdevice_reset(tas_hda->priv);665666ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);667if (ret) {668dev_err(tas_hda->dev, "Register component failed: %d\n", ret);669pm_runtime_disable(tas_hda->dev);670}671672err:673if (ret)674tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);675return ret;676}677678static void tas2781_hda_i2c_remove(struct i2c_client *clt)679{680tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);681}682683static int tas2781_runtime_suspend(struct device *dev)684{685struct tas2781_hda *tas_hda = dev_get_drvdata(dev);686687dev_dbg(tas_hda->dev, "Runtime Suspend\n");688689mutex_lock(&tas_hda->priv->codec_lock);690691/* The driver powers up the amplifiers at module load time.692* Stop the playback if it's unused.693*/694if (tas_hda->priv->playback_started) {695tasdevice_tuning_switch(tas_hda->priv, 1);696tas_hda->priv->playback_started = false;697}698699mutex_unlock(&tas_hda->priv->codec_lock);700701return 0;702}703704static int tas2781_runtime_resume(struct device *dev)705{706struct tas2781_hda *tas_hda = dev_get_drvdata(dev);707708dev_dbg(tas_hda->dev, "Runtime Resume\n");709710mutex_lock(&tas_hda->priv->codec_lock);711712tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);713714mutex_unlock(&tas_hda->priv->codec_lock);715716return 0;717}718719static int tas2781_system_suspend(struct device *dev)720{721struct tas2781_hda *tas_hda = dev_get_drvdata(dev);722723dev_dbg(tas_hda->priv->dev, "System Suspend\n");724725mutex_lock(&tas_hda->priv->codec_lock);726727/* Shutdown chip before system suspend */728if (tas_hda->priv->playback_started)729tasdevice_tuning_switch(tas_hda->priv, 1);730731mutex_unlock(&tas_hda->priv->codec_lock);732733/*734* Reset GPIO may be shared, so cannot reset here.735* However beyond this point, amps may be powered down.736*/737return 0;738}739740static int tas2781_system_resume(struct device *dev)741{742struct tas2781_hda *tas_hda = dev_get_drvdata(dev);743int i;744745dev_dbg(tas_hda->priv->dev, "System Resume\n");746747mutex_lock(&tas_hda->priv->codec_lock);748749for (i = 0; i < tas_hda->priv->ndev; i++) {750tas_hda->priv->tasdevice[i].cur_book = -1;751tas_hda->priv->tasdevice[i].cur_prog = -1;752tas_hda->priv->tasdevice[i].cur_conf = -1;753}754tasdevice_reset(tas_hda->priv);755tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);756757if (tas_hda->priv->playback_started)758tasdevice_tuning_switch(tas_hda->priv, 0);759760mutex_unlock(&tas_hda->priv->codec_lock);761762return 0;763}764765static const struct dev_pm_ops tas2781_hda_pm_ops = {766RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)767SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)768};769770static const struct i2c_device_id tas2781_hda_i2c_id[] = {771{ "tas2781-hda" },772{}773};774775static const struct acpi_device_id tas2781_acpi_hda_match[] = {776{"INT8866", 0 },777{"TIAS2781", 0 },778{"TXNW2770", 0 },779{"TXNW2781", 0 },780{}781};782MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);783784static struct i2c_driver tas2781_hda_i2c_driver = {785.driver = {786.name = "tas2781-hda",787.acpi_match_table = tas2781_acpi_hda_match,788.pm = &tas2781_hda_pm_ops,789},790.id_table = tas2781_hda_i2c_id,791.probe = tas2781_hda_i2c_probe,792.remove = tas2781_hda_i2c_remove,793};794module_i2c_driver(tas2781_hda_i2c_driver);795796MODULE_DESCRIPTION("TAS2781 HDA Driver");797MODULE_AUTHOR("Shenghao Ding, TI, <[email protected]>");798MODULE_LICENSE("GPL");799MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");800MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");801802803