linux/sound/soc/sof/sof-pci-dev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//
  10
  11#include <linux/firmware.h>
  12#include <linux/dmi.h>
  13#include <linux/module.h>
  14#include <linux/pci.h>
  15#include <linux/pm_runtime.h>
  16#include <sound/soc-acpi.h>
  17#include <sound/soc-acpi-intel-match.h>
  18#include <sound/sof.h>
  19#include "ops.h"
  20#include "sof-pci-dev.h"
  21
  22static char *fw_path;
  23module_param(fw_path, charp, 0444);
  24MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
  25
  26static char *tplg_path;
  27module_param(tplg_path, charp, 0444);
  28MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
  29
  30static int sof_pci_debug;
  31module_param_named(sof_pci_debug, sof_pci_debug, int, 0444);
  32MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)");
  33
  34static const char *sof_override_tplg_name;
  35
  36#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
  37
  38static int sof_tplg_cb(const struct dmi_system_id *id)
  39{
  40        sof_override_tplg_name = id->driver_data;
  41        return 1;
  42}
  43
  44static const struct dmi_system_id sof_tplg_table[] = {
  45        {
  46                .callback = sof_tplg_cb,
  47                .matches = {
  48                        DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"),
  49                        DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
  50                },
  51                .driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg",
  52        },
  53        {
  54                .callback = sof_tplg_cb,
  55                .matches = {
  56                        DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  57                        DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
  58                        DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
  59                },
  60                .driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg",
  61        },
  62        {}
  63};
  64
  65static const struct dmi_system_id community_key_platforms[] = {
  66        {
  67                .ident = "Up Squared",
  68                .matches = {
  69                        DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
  70                        DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
  71                }
  72        },
  73        {
  74                .ident = "Up Extreme",
  75                .matches = {
  76                        DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
  77                        DMI_MATCH(DMI_BOARD_NAME, "UP-WHL01"),
  78                }
  79        },
  80        {
  81                .ident = "Google Chromebooks",
  82                .matches = {
  83                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
  84                }
  85        },
  86        {},
  87};
  88
  89const struct dev_pm_ops sof_pci_pm = {
  90        .prepare = snd_sof_prepare,
  91        .complete = snd_sof_complete,
  92        SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
  93        SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
  94                           snd_sof_runtime_idle)
  95};
  96EXPORT_SYMBOL_NS(sof_pci_pm, SND_SOC_SOF_PCI_DEV);
  97
  98static void sof_pci_probe_complete(struct device *dev)
  99{
 100        dev_dbg(dev, "Completing SOF PCI probe");
 101
 102        if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)
 103                return;
 104
 105        /* allow runtime_pm */
 106        pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
 107        pm_runtime_use_autosuspend(dev);
 108
 109        /*
 110         * runtime pm for pci device is "forbidden" by default.
 111         * so call pm_runtime_allow() to enable it.
 112         */
 113        pm_runtime_allow(dev);
 114
 115        /* mark last_busy for pm_runtime to make sure not suspend immediately */
 116        pm_runtime_mark_last_busy(dev);
 117
 118        /* follow recommendation in pci-driver.c to decrement usage counter */
 119        pm_runtime_put_noidle(dev);
 120}
 121
 122int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 123{
 124        struct device *dev = &pci->dev;
 125        const struct sof_dev_desc *desc =
 126                (const struct sof_dev_desc *)pci_id->driver_data;
 127        struct snd_sof_pdata *sof_pdata;
 128        int ret;
 129
 130        dev_dbg(&pci->dev, "PCI DSP detected");
 131
 132        if (!desc->ops) {
 133                dev_err(dev, "error: no matching PCI descriptor ops\n");
 134                return -ENODEV;
 135        }
 136
 137        sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
 138        if (!sof_pdata)
 139                return -ENOMEM;
 140
 141        ret = pcim_enable_device(pci);
 142        if (ret < 0)
 143                return ret;
 144
 145        ret = pci_request_regions(pci, "Audio DSP");
 146        if (ret < 0)
 147                return ret;
 148
 149        sof_pdata->name = pci_name(pci);
 150        sof_pdata->desc = desc;
 151        sof_pdata->dev = dev;
 152        sof_pdata->fw_filename = desc->default_fw_filename;
 153
 154        /*
 155         * for platforms using the SOF community key, change the
 156         * default path automatically to pick the right files from the
 157         * linux-firmware tree. This can be overridden with the
 158         * fw_path kernel parameter, e.g. for developers.
 159         */
 160
 161        /* alternate fw and tplg filenames ? */
 162        if (fw_path) {
 163                sof_pdata->fw_filename_prefix = fw_path;
 164
 165                dev_dbg(dev,
 166                        "Module parameter used, changed fw path to %s\n",
 167                        sof_pdata->fw_filename_prefix);
 168
 169        } else if (dmi_check_system(community_key_platforms)) {
 170                sof_pdata->fw_filename_prefix =
 171                        devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
 172                                       sof_pdata->desc->default_fw_path,
 173                                       "community");
 174
 175                dev_dbg(dev,
 176                        "Platform uses community key, changed fw path to %s\n",
 177                        sof_pdata->fw_filename_prefix);
 178        } else {
 179                sof_pdata->fw_filename_prefix =
 180                        sof_pdata->desc->default_fw_path;
 181        }
 182
 183        if (tplg_path)
 184                sof_pdata->tplg_filename_prefix = tplg_path;
 185        else
 186                sof_pdata->tplg_filename_prefix =
 187                        sof_pdata->desc->default_tplg_path;
 188
 189        dmi_check_system(sof_tplg_table);
 190        if (sof_override_tplg_name)
 191                sof_pdata->tplg_filename = sof_override_tplg_name;
 192
 193        /* set callback to be called on successful device probe to enable runtime_pm */
 194        sof_pdata->sof_probe_complete = sof_pci_probe_complete;
 195
 196        /* call sof helper for DSP hardware probe */
 197        ret = snd_sof_device_probe(dev, sof_pdata);
 198        if (ret)
 199                pci_release_regions(pci);
 200
 201        return ret;
 202}
 203EXPORT_SYMBOL_NS(sof_pci_probe, SND_SOC_SOF_PCI_DEV);
 204
 205void sof_pci_remove(struct pci_dev *pci)
 206{
 207        /* call sof helper for DSP hardware remove */
 208        snd_sof_device_remove(&pci->dev);
 209
 210        /* follow recommendation in pci-driver.c to increment usage counter */
 211        if (snd_sof_device_probe_completed(&pci->dev) &&
 212            !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
 213                pm_runtime_get_noresume(&pci->dev);
 214
 215        /* release pci regions and disable device */
 216        pci_release_regions(pci);
 217}
 218EXPORT_SYMBOL_NS(sof_pci_remove, SND_SOC_SOF_PCI_DEV);
 219
 220void sof_pci_shutdown(struct pci_dev *pci)
 221{
 222        snd_sof_device_shutdown(&pci->dev);
 223}
 224EXPORT_SYMBOL_NS(sof_pci_shutdown, SND_SOC_SOF_PCI_DEV);
 225
 226MODULE_LICENSE("Dual BSD/GPL");
 227