From patchwork Thu Feb 27 22:31:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Louis Bossart X-Patchwork-Id: 193438 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45452C3F2C6 for ; Thu, 27 Feb 2020 22:34:16 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C2E4524650 for ; Thu, 27 Feb 2020 22:34:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=alsa-project.org header.i=@alsa-project.org header.b="IjCG+v8i" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C2E4524650 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 22D3416C9; Thu, 27 Feb 2020 23:33:24 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 22D3416C9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1582842854; bh=cxJXnJFhaxMHjqgurIx5E58SpCEoAYsIy8WnPue8wtg=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=IjCG+v8iBgJEIMkw1P3bdBszrsBBdAQFqJpGar48PfV4WmLnS5WES6uO44BWpI8EK JZseHfj2VSWDI9I2XPuDKJuxhx2WSPWtqco0WoNB3zMBIZCf6e+w4ZDIEP0AkBsomk P68TyUHEk8NImACbGF8Mm9McwkxFXiTswtLdfvtM= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 08911F80161; Thu, 27 Feb 2020 23:32:35 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id A3BD1F80278; Thu, 27 Feb 2020 23:32:30 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id DEBC6F80125 for ; Thu, 27 Feb 2020 23:32:24 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz DEBC6F80125 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2020 14:32:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,493,1574150400"; d="scan'208";a="411194797" Received: from azeira-mobl.amr.corp.intel.com (HELO pbossart-mobl3.amr.corp.intel.com) ([10.251.147.250]) by orsmga005.jf.intel.com with ESMTP; 27 Feb 2020 14:32:21 -0800 From: Pierre-Louis Bossart To: alsa-devel@alsa-project.org Subject: [PATCH 1/8] soundwire: bus_type: add master_device/driver support Date: Thu, 27 Feb 2020 16:31:59 -0600 Message-Id: <20200227223206.5020-2-pierre-louis.bossart@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> References: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> MIME-Version: 1.0 Cc: Pierre-Louis Bossart , tiwai@suse.de, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, Ranjani Sridharan , Hui Wang , vkoul@kernel.org, broonie@kernel.org, srinivas.kandagatla@linaro.org, jank@cadence.com, slawomir.blauciak@intel.com, Sanyog Kale , Bard liao , Rander Wang X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" In the existing SoundWire code, Master Devices are not explicitly represented - only SoundWire Slave Devices are exposed (the use of capital letters follows the SoundWire specification conventions). The SoundWire Master Device provides the clock, synchronization information and command/control channels. When multiple links are supported, a Controller may expose more than one Master Device; they are typically embedded inside a larger audio cluster (be it in an SOC/chipset or an external audio codec), and we need to describe it using the Linux device and driver model. This will allow for configuration functions to account for external dependencies such as power rails, clock sources or wake-up mechanisms. This transition will also allow for better sysfs support without the reference count issues mentioned in the initial reviews. In this patch, we convert the existing code to use an explicit sdw_slave_type, then define new objects (sdw_master_device and sdw_master_driver). A parent (such as the Intel audio controller or its equivalent on Qualcomm devices) would use sdw_master_device_add() to create the device, passing a driver name as a parameter. The master device would be released when device_unregister() is invoked by the parent. Note that since there is no standard for the Master host-facing interface, so the bus matching relies on a simple string matching (as previously done with platform devices). The 'Master Device' driver exposes callbacks for probe/startup/shutdown/remove/process_wake. The startup and process wake need to be called by the parent directly (using wrappers), while the probe/shutdown/remove are handled by the SoundWire bus core upon device creation and release. Additional callbacks will be added in the future for e.g. autonomous clock stop modes. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/Makefile | 2 +- drivers/soundwire/bus_type.c | 141 +++++++++++++++++++++++++++-- drivers/soundwire/master.c | 100 ++++++++++++++++++++ drivers/soundwire/slave.c | 7 +- include/linux/soundwire/sdw.h | 76 ++++++++++++++++ include/linux/soundwire/sdw_type.h | 36 +++++++- 6 files changed, 351 insertions(+), 11 deletions(-) create mode 100644 drivers/soundwire/master.c diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index e2cdff990e9f..7319918e0aec 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -4,7 +4,7 @@ # #Bus Objs -soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o +soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o ifdef CONFIG_DEBUG_FS diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 17f096dd6806..e610f1d3b840 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -33,13 +33,33 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); - struct sdw_driver *drv = drv_to_sdw_driver(ddrv); + struct sdw_slave *slave; + struct sdw_driver *drv; + struct sdw_master_device *md; + struct sdw_master_driver *mdrv; + int ret = 0; - return !!sdw_get_device_id(slave, drv); + if (is_sdw_slave(dev)) { + slave = dev_to_sdw_dev(dev); + drv = drv_to_sdw_driver(ddrv); + + ret = !!sdw_get_device_id(slave, drv); + } else { + md = dev_to_sdw_master_device(dev); + mdrv = drv_to_sdw_master_driver(ddrv); + + /* + * we don't have any hardware information so + * match with a hopefully unique string + */ + ret = !strncmp(md->master_name, mdrv->driver.name, + strlen(md->master_name)); + } + return ret; } -int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) +static int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, + size_t size) { /* modalias is sdw:mp */ @@ -47,12 +67,31 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) slave->id.mfg_id, slave->id.part_id); } +static int sdw_master_modalias(const struct sdw_master_device *md, + char *buf, size_t size) +{ + /* modalias is sdw: since we don't have any hardware info */ + + return snprintf(buf, size, "sdw:%s\n", + md->master_name); +} + static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave; + struct sdw_master_device *md; char modalias[32]; - sdw_slave_modalias(slave, modalias, sizeof(modalias)); + if (is_sdw_slave(dev)) { + slave = dev_to_sdw_dev(dev); + + sdw_slave_modalias(slave, modalias, sizeof(modalias)); + + } else { + md = dev_to_sdw_master_device(dev); + + sdw_master_modalias(md, modalias, sizeof(modalias)); + } if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; @@ -113,8 +152,6 @@ static int sdw_drv_probe(struct device *dev) slave->probed = true; complete(&slave->probe_complete); - dev_dbg(dev, "probe complete\n"); - return 0; } @@ -181,6 +218,94 @@ void sdw_unregister_driver(struct sdw_driver *drv) } EXPORT_SYMBOL_GPL(sdw_unregister_driver); +static int sdw_master_drv_probe(struct device *dev) +{ + struct sdw_master_device *md = dev_to_sdw_master_device(dev); + struct sdw_master_driver *mdrv = drv_to_sdw_master_driver(dev->driver); + int ret; + + /* + * attach to power domain but don't turn on (last arg) + */ + ret = dev_pm_domain_attach(dev, false); + if (ret) + return ret; + + ret = mdrv->probe(md, md->pdata); + if (ret) { + dev_err(dev, "Probe of %s failed: %d\n", + mdrv->driver.name, ret); + dev_pm_domain_detach(dev, false); + return ret; + } + + return 0; +} + +static int sdw_master_drv_remove(struct device *dev) +{ + struct sdw_master_device *md = dev_to_sdw_master_device(dev); + struct sdw_master_driver *mdrv = drv_to_sdw_master_driver(dev->driver); + int ret = 0; + + if (mdrv->remove) + ret = mdrv->remove(md); + + dev_pm_domain_detach(dev, false); + + return ret; +} + +static void sdw_master_drv_shutdown(struct device *dev) +{ + struct sdw_master_device *md = dev_to_sdw_master_device(dev); + struct sdw_master_driver *mdrv = drv_to_sdw_master_driver(dev->driver); + + if (mdrv->shutdown) + mdrv->shutdown(md); +} + +/** + * __sdw_register_master_driver() - register a SoundWire Master driver + * @mdrv: 'Master driver' to register + * @owner: owning module/driver + * + * Return: zero on success, else a negative error code. + */ +int __sdw_register_master_driver(struct sdw_master_driver *mdrv, + struct module *owner) +{ + mdrv->driver.bus = &sdw_bus_type; + + if (!mdrv->probe) { + pr_err("driver %s didn't provide SDW probe routine\n", + mdrv->driver.name); + return -EINVAL; + } + + mdrv->driver.owner = owner; + mdrv->driver.probe = sdw_master_drv_probe; + + if (mdrv->remove) + mdrv->driver.remove = sdw_master_drv_remove; + + if (mdrv->shutdown) + mdrv->driver.shutdown = sdw_master_drv_shutdown; + + return driver_register(&mdrv->driver); +} +EXPORT_SYMBOL_GPL(__sdw_register_master_driver); + +/** + * sdw_unregister_master_driver() - unregisters the SoundWire Master driver + * @mdrv: driver to unregister + */ +void sdw_unregister_master_driver(struct sdw_master_driver *mdrv) +{ + driver_unregister(&mdrv->driver); +} +EXPORT_SYMBOL_GPL(sdw_unregister_master_driver); + static int __init sdw_bus_init(void) { sdw_debugfs_init(); diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c new file mode 100644 index 000000000000..1f3c376327f9 --- /dev/null +++ b/drivers/soundwire/master.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: (GPL-2.0) +// Copyright(c) 2019-2020 Intel Corporation. + +#include +#include +#include +#include +#include "bus.h" + +static void sdw_master_device_release(struct device *dev) +{ + struct sdw_master_device *md = dev_to_sdw_master_device(dev); + + kfree(md); +} + +struct device_type sdw_master_type = { + .name = "soundwire_master", + .release = sdw_master_device_release, +}; + +struct sdw_master_device +*sdw_master_device_add(const char *master_name, + struct device *parent, + struct fwnode_handle *fwnode, + int link_id, + void *pdata) +{ + struct sdw_master_device *md; + int ret; + + md = kzalloc(sizeof(*md), GFP_KERNEL); + if (!md) + return ERR_PTR(-ENOMEM); + + md->link_id = link_id; + md->pdata = pdata; + md->master_name = master_name; + + init_completion(&md->probe_complete); + + md->dev.parent = parent; + md->dev.fwnode = fwnode; + md->dev.bus = &sdw_bus_type; + md->dev.type = &sdw_master_type; + md->dev.dma_mask = md->dev.parent->dma_mask; + dev_set_name(&md->dev, "sdw-master-%d", md->link_id); + + ret = device_register(&md->dev); + if (ret) { + dev_err(parent, "Failed to add master: ret %d\n", ret); + /* + * On err, don't free but drop ref as this will be freed + * when release method is invoked. + */ + put_device(&md->dev); + return ERR_PTR(-ENOMEM); + } + + return md; +} +EXPORT_SYMBOL_GPL(sdw_master_device_add); + +int sdw_master_device_startup(struct sdw_master_device *md) +{ + struct sdw_master_driver *mdrv; + struct device *dev; + int ret = 0; + + if (IS_ERR_OR_NULL(md)) + return -EINVAL; + + dev = &md->dev; + mdrv = drv_to_sdw_master_driver(dev->driver); + + if (mdrv && mdrv->startup) + ret = mdrv->startup(md); + + return ret; +} +EXPORT_SYMBOL_GPL(sdw_master_device_startup); + +int sdw_master_device_process_wake_event(struct sdw_master_device *md) +{ + struct sdw_master_driver *mdrv; + struct device *dev; + int ret = 0; + + if (IS_ERR_OR_NULL(md)) + return -EINVAL; + + dev = &md->dev; + mdrv = drv_to_sdw_master_driver(dev->driver); + + if (mdrv && mdrv->process_wake_event) + ret = mdrv->process_wake_event(md); + + return ret; +} +EXPORT_SYMBOL_GPL(sdw_master_device_process_wake_event); diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index aace57fae7f8..7ca4f2d9bfa6 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -14,6 +14,11 @@ static void sdw_slave_release(struct device *dev) kfree(slave); } +struct device_type sdw_slave_type = { + .name = "sdw_slave", + .release = sdw_slave_release, +}; + static int sdw_slave_add(struct sdw_bus *bus, struct sdw_slave_id *id, struct fwnode_handle *fwnode) { @@ -41,9 +46,9 @@ static int sdw_slave_add(struct sdw_bus *bus, id->class_id, id->unique_id); } - slave->dev.release = sdw_slave_release; slave->dev.bus = &sdw_bus_type; slave->dev.of_node = of_node_get(to_of_node(fwnode)); + slave->dev.type = &sdw_slave_type; slave->bus = bus; slave->status = SDW_SLAVE_UNATTACHED; init_completion(&slave->enumeration_complete); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index ee349a4c5349..a64fde620ae6 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -630,6 +630,31 @@ struct sdw_slave { #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) +/** + * struct sdw_master_device - SoundWire 'Master Device' representation + * + * @dev: Linux device for this Master + * @master_name: Linux driver name + * @driver: Linux driver for this Master (set by SoundWire core during probe) + * @probe_complete: used by parent if synchronous probe behavior is needed + * @link_id: link index as defined by MIPI DisCo specification + * @pm_runtime_suspended: flag to restore pm_runtime state after system resume + * @pdata: private data typically provided with sdw_master_device_add() + */ + +struct sdw_master_device { + struct device dev; + const char *master_name; + struct sdw_master_driver *driver; + struct completion probe_complete; + int link_id; + bool pm_runtime_suspended; + void *pdata; +}; + +#define dev_to_sdw_master_device(d) \ + container_of(d, struct sdw_master_device, dev) + struct sdw_driver { const char *name; @@ -644,6 +669,26 @@ struct sdw_driver { struct device_driver driver; }; +/** + * struct sdw_master_driver - SoundWire 'Master Device' driver + * + * @probe: initializations and allocation (hardware may not be enabled yet) + * @startup: initialization handled after the hardware is enabled, all + * clock/power dependencies are available (optional) + * @shutdown: cleanups before hardware is disabled (optional) + * @remove: free all remaining resources + * @process_wake_event: handle external wake (optional) + * @driver: baseline structure used for name/PM hooks. + */ +struct sdw_master_driver { + int (*probe)(struct sdw_master_device *md, void *link_ctx); + int (*startup)(struct sdw_master_device *md); + int (*shutdown)(struct sdw_master_device *md); + int (*remove)(struct sdw_master_device *md); + int (*process_wake_event)(struct sdw_master_device *md); + struct device_driver driver; +}; + #define SDW_SLAVE_ENTRY(_mfg_id, _part_id, _drv_data) \ { .mfg_id = (_mfg_id), .part_id = (_part_id), \ .driver_data = (unsigned long)(_drv_data) } @@ -833,6 +878,37 @@ struct sdw_bus { int sdw_add_bus_master(struct sdw_bus *bus); void sdw_delete_bus_master(struct sdw_bus *bus); +/** + * sdw_master_device_add() - create a Linux Master Device representation. + * + * @master_name: Linux driver name + * @parent: the parent Linux device (e.g. a PCI device) + * @fwnode: the parent fwnode (e.g. an ACPI companion device to the parent) + * @link_id: link index as defined by MIPI DisCo specification + * @pdata: private data (e.g. register base, offsets, platform quirks, etc). + */ +struct sdw_master_device +*sdw_master_device_add(const char *master_name, + struct device *parent, + struct fwnode_handle *fwnode, + int link_id, + void *pdata); + +/** + * sdw_master_device_startup() - startup hardware + * + * @md: Linux Soundwire master device + */ +int sdw_master_device_startup(struct sdw_master_device *md); + +/** + * sdw_master_device_process_wake_event() - handle external wake + * event, e.g. handled at the PCI level + * + * @md: Linux Soundwire master device + */ +int sdw_master_device_process_wake_event(struct sdw_master_device *md); + /** * sdw_port_config: Master or Slave Port configuration * diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h index aaa7f4267c14..331ba58bda27 100644 --- a/include/linux/soundwire/sdw_type.h +++ b/include/linux/soundwire/sdw_type.h @@ -5,16 +5,36 @@ #define __SOUNDWIRE_TYPES_H extern struct bus_type sdw_bus_type; +extern struct device_type sdw_slave_type; +extern struct device_type sdw_master_type; + +static inline int is_sdw_slave(const struct device *dev) +{ + return dev->type == &sdw_slave_type; +} #define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver) #define sdw_register_driver(drv) \ __sdw_register_driver(drv, THIS_MODULE) +static inline int is_sdw_master_device(const struct device *dev) +{ + return dev->type == &sdw_master_type; +} + +#define drv_to_sdw_master_driver(_drv) \ + container_of(_drv, struct sdw_master_driver, driver) + +#define sdw_register_master_driver(drv) \ + __sdw_register_master_driver(drv, THIS_MODULE) + int __sdw_register_driver(struct sdw_driver *drv, struct module *owner); void sdw_unregister_driver(struct sdw_driver *drv); -int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); +int __sdw_register_master_driver(struct sdw_master_driver *mdrv, + struct module *owner); +void sdw_unregister_master_driver(struct sdw_master_driver *mdrv); /** * module_sdw_driver() - Helper macro for registering a Soundwire driver @@ -27,4 +47,18 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); #define module_sdw_driver(__sdw_driver) \ module_driver(__sdw_driver, sdw_register_driver, \ sdw_unregister_driver) + +/** + * module_sdw_master_driver() - Helper macro for registering a Soundwire + * Master driver + * @__sdw_master_driver: soundwire Master driver struct + * + * Helper macro for Soundwire Master drivers which do not do anything special in + * module init/exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit() + */ +#define module_sdw_master_driver(__sdw_master_driver) \ + module_driver(__sdw_master_driver, sdw_register_master_driver, \ + sdw_unregister_master_driver) + #endif /* __SOUNDWIRE_TYPES_H */ From patchwork Thu Feb 27 22:32:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Louis Bossart X-Patchwork-Id: 193437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DA17C3F2C2 for ; Thu, 27 Feb 2020 22:35:48 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A8D9F246A2 for ; Thu, 27 Feb 2020 22:35:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=alsa-project.org header.i=@alsa-project.org header.b="cCVG3lmL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A8D9F246A2 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 03B1B16D2; Thu, 27 Feb 2020 23:34:56 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 03B1B16D2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1582842946; bh=ZcWKMuooExomcFQKrOITrqcMb/Wl05zWCaJJ15rx8co=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=cCVG3lmLhzIsQ93+yAT1fdl/zNV5a4xiJ0is1LfLSVk8zU9B5UO5HI+7HOQr5zZqv CPIq1cPPg10BBdMaMC9LbxmweWuMcEibquuvsSkpe4CZp5jC1pGmdz8/9brk9yTTPB XsM96I2S636z+xLtLJQctNoyGcIpeVJ4GcvknLJc= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 1DE24F8029A; Thu, 27 Feb 2020 23:32:41 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id DB486F80161; Thu, 27 Feb 2020 23:32:32 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 08666F80089 for ; Thu, 27 Feb 2020 23:32:27 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 08666F80089 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2020 14:32:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,493,1574150400"; d="scan'208";a="411194826" Received: from azeira-mobl.amr.corp.intel.com (HELO pbossart-mobl3.amr.corp.intel.com) ([10.251.147.250]) by orsmga005.jf.intel.com with ESMTP; 27 Feb 2020 14:32:25 -0800 From: Pierre-Louis Bossart To: alsa-devel@alsa-project.org Subject: [PATCH 3/8] soundwire: intel_init: add implementation of sdw_intel_enable_irq() Date: Thu, 27 Feb 2020 16:32:01 -0600 Message-Id: <20200227223206.5020-4-pierre-louis.bossart@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> References: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> MIME-Version: 1.0 Cc: Pierre-Louis Bossart , tiwai@suse.de, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, Ranjani Sridharan , Hui Wang , vkoul@kernel.org, broonie@kernel.org, srinivas.kandagatla@linaro.org, jank@cadence.com, slawomir.blauciak@intel.com, Sanyog Kale , Bard liao , Rander Wang X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" This function is required to enable all interrupts across all links. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel_init.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index a6ff7d2ae8be..88ad2a1637ad 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -141,6 +141,30 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) return 0; } +#define HDA_DSP_REG_ADSPIC2 (0x10) +#define HDA_DSP_REG_ADSPIS2 (0x14) +#define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) + +/** + * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ + * @mmio_base: The mmio base of the control register + * @enable: true if enable + */ +void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) +{ + u32 val; + + val = readl(mmio_base + HDA_DSP_REG_ADSPIC2); + + if (enable) + val |= HDA_DSP_REG_ADSPIC2_SNDW; + else + val &= ~HDA_DSP_REG_ADSPIC2_SNDW; + + writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); +} +EXPORT_SYMBOL(sdw_intel_enable_irq); + static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) { From patchwork Thu Feb 27 22:32:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Louis Bossart X-Patchwork-Id: 193436 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A668CC3F2C6 for ; Thu, 27 Feb 2020 22:36:44 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 32A46246A2 for ; Thu, 27 Feb 2020 22:36:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=alsa-project.org header.i=@alsa-project.org header.b="cfWHYm0s" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 32A46246A2 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 831C116E4; Thu, 27 Feb 2020 23:35:52 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 831C116E4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1582843002; bh=s8Kqpo92Sq4aD6y/WnqEU500+LZHXihlZeKWHOjzlFY=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=cfWHYm0sxDb/2fTUUL6xn0c3uc3gf5cmQL48cyztZpeBsB4HfKDXrBe6UN9VlZ7N9 ES4hFtZoAE43W1jnFfgYQCKgXhpKs8jJ9c7wfkEuE2QlnxRzrUcr1UBzdgEB7y63wi MVsvVdmG75qoEJCjhJwTDMwbxtY58zxqqRrzxGoE= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 03842F802A8; Thu, 27 Feb 2020 23:32:44 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id F0D4AF8028C; Thu, 27 Feb 2020 23:32:37 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 7813AF80278 for ; Thu, 27 Feb 2020 23:32:34 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 7813AF80278 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2020 14:32:34 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,493,1574150400"; d="scan'208";a="411194857" Received: from azeira-mobl.amr.corp.intel.com (HELO pbossart-mobl3.amr.corp.intel.com) ([10.251.147.250]) by orsmga005.jf.intel.com with ESMTP; 27 Feb 2020 14:32:32 -0800 From: Pierre-Louis Bossart To: alsa-devel@alsa-project.org Subject: [PATCH 6/8] soundwire: intel: add helpers for link power down and shim wake Date: Thu, 27 Feb 2020 16:32:04 -0600 Message-Id: <20200227223206.5020-7-pierre-louis.bossart@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> References: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> MIME-Version: 1.0 Cc: Pierre-Louis Bossart , tiwai@suse.de, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, Ranjani Sridharan , Hui Wang , vkoul@kernel.org, broonie@kernel.org, srinivas.kandagatla@linaro.org, jank@cadence.com, slawomir.blauciak@intel.com, Sanyog Kale , Bard liao , Rander Wang X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" These routines are required for power management Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index d5533564195a..eafa2016c76d 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -362,6 +362,59 @@ static int intel_shim_init(struct sdw_intel *sdw) return ret; } +static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) +{ + void __iomem *shim = sdw->link_res->shim; + unsigned int link_id = sdw->instance; + u16 wake_en, wake_sts; + + if (wake_enable) { + /* Enable the wakeup */ + intel_writew(shim, SDW_SHIM_WAKEEN, + (SDW_SHIM_WAKEEN_ENABLE << link_id)); + } else { + /* Disable the wake up interrupt */ + wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); + wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); + + /* Clear wake status */ + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); + } +} + +static int intel_link_power_down(struct sdw_intel *sdw) +{ + int link_control, spa_mask, cpa_mask, ret; + unsigned int link_id = sdw->instance; + void __iomem *shim = sdw->link_res->shim; + u16 ioctl; + + /* Glue logic */ + ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); + ioctl |= SDW_SHIM_IOCTL_BKE; + ioctl |= SDW_SHIM_IOCTL_COE; + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + ioctl &= ~(SDW_SHIM_IOCTL_MIF); + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + /* Link power down sequence */ + link_control = intel_readl(shim, SDW_SHIM_LCTL); + spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id); + cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); + link_control &= spa_mask; + + ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + if (ret < 0) + return ret; + + sdw->cdns.link_up = false; + return 0; +} + /* * PDI routines */ From patchwork Thu Feb 27 22:32:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Louis Bossart X-Patchwork-Id: 193435 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1EBB2C3F2C6 for ; Thu, 27 Feb 2020 22:38:01 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9B16D246A1 for ; Thu, 27 Feb 2020 22:38:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=alsa-project.org header.i=@alsa-project.org header.b="ul6YNKXc" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9B16D246A1 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id ED6F516C7; Thu, 27 Feb 2020 23:37:08 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz ED6F516C7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1582843079; bh=y8SacCxTjk8VJzJNDLjXrQIe7Ton5BaqLu9iEus3Gmw=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=ul6YNKXcSykhZai/cA/OLUWyfuYSNx6XfPxf65gGbFDadBSSQ/5/O9HeY62qiVmbB fVqLJD3+M2vH1vD3MXhn8kpcP0AFKGujGMhn9XBo1oJ+qp+sIsL7Ca13Uo/diFlJSl NioSpZdxjR6CrNhqbgK6NlC8PYuqvSuc3gomuNsY= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 9CF85F802E1; Thu, 27 Feb 2020 23:32:47 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id EA161F802A2; Thu, 27 Feb 2020 23:32:41 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 773A0F8028C for ; Thu, 27 Feb 2020 23:32:37 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 773A0F8028C X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2020 14:32:36 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,493,1574150400"; d="scan'208";a="411194879" Received: from azeira-mobl.amr.corp.intel.com (HELO pbossart-mobl3.amr.corp.intel.com) ([10.251.147.250]) by orsmga005.jf.intel.com with ESMTP; 27 Feb 2020 14:32:34 -0800 From: Pierre-Louis Bossart To: alsa-devel@alsa-project.org Subject: [PATCH 7/8] soundwire: intel: add wake interrupt support Date: Thu, 27 Feb 2020 16:32:05 -0600 Message-Id: <20200227223206.5020-8-pierre-louis.bossart@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> References: <20200227223206.5020-1-pierre-louis.bossart@linux.intel.com> MIME-Version: 1.0 Cc: Pierre-Louis Bossart , tiwai@suse.de, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, Ranjani Sridharan , Hui Wang , vkoul@kernel.org, broonie@kernel.org, srinivas.kandagatla@linaro.org, jank@cadence.com, slawomir.blauciak@intel.com, Sanyog Kale , Rander Wang , Bard liao , Rander Wang X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" From: Rander Wang When system is suspended in clock stop mode on intel platforms, both master and slave are in clock stop mode and soundwire bus is taken over by a glue hardware. The bus message for jack event is processed by this glue hardware, which will trigger an interrupt to resume audio pci device. Then audio pci driver will resume soundwire master and slave, transfer bus ownership to master, finally slave will report jack event to master and codec driver is triggered to check jack status. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 45 ++++++++++++++++++++++++++++++++++ drivers/soundwire/intel_init.c | 12 +++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index eafa2016c76d..4cc6c857dd09 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1255,6 +1255,50 @@ static int intel_master_remove(struct sdw_master_device *md) return 0; } +static int intel_master_process_wakeen_event(struct sdw_master_device *md) +{ + struct sdw_intel *sdw; + struct sdw_slave *slave; + struct sdw_bus *bus; + void __iomem *shim; + u16 wake_sts; + + sdw = md->pdata; + + if (sdw->cdns.bus.prop.hw_disabled) { + dev_info(&md->dev, + "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return 0; + } + + shim = sdw->link_res->shim; + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + + if (!(wake_sts & BIT(sdw->instance))) + return 0; + + /* disable WAKEEN interrupt ASAP to prevent interrupt flood */ + intel_shim_wake(sdw, false); + + bus = &sdw->cdns.bus; + + /* + * wake up master and slave so that slave can notify master + * the wakeen event and let codec driver check codec status + */ + list_for_each_entry(slave, &bus->slaves, node) { + if (slave->prop.wake_capable) { + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + pm_request_resume(&slave->dev); + } + } + + return 0; +} static struct sdw_master_driver intel_sdw_driver = { .driver = { @@ -1265,6 +1309,7 @@ static struct sdw_master_driver intel_sdw_driver = { .probe = intel_master_probe, .startup = intel_master_startup, .remove = intel_master_remove, + .process_wake_event = intel_master_process_wakeen_event, }; module_sdw_master_driver(intel_sdw_driver); diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 954b21b4712d..91ec91127f2a 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -413,5 +413,17 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) } EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); +void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) +{ + struct sdw_intel_link_res *link; + + if (!ctx->links) + return; + + list_for_each_entry(link, &ctx->link_list, list) + sdw_master_device_process_wake_event(link->md); +} +EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library");