mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
soundwire: intel: move bus common sequences to different file
Now that the bus start/stop/clock_stop sequences use the ops, we can move them to a different file to reuse them. Note that we could in theory remove the abstraction for all those sequences and directly call the functions in intel_auxdevice.c. To allow for more flexibility and have means to special-case new platforms, we decided to keep the abstraction. If in time it becomes clear there is no benefit the abstraction will be simplified. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20230314015410.487311-9-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
90e4632a6f
commit
1a1a6a692e
@ -20,7 +20,8 @@ soundwire-cadence-y := cadence_master.o
|
||||
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o
|
||||
|
||||
#Intel driver
|
||||
soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o
|
||||
soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o \
|
||||
intel_bus_common.o
|
||||
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
|
||||
|
||||
#Qualcomm driver
|
||||
|
@ -1122,205 +1122,6 @@ static int intel_register_dai(struct sdw_intel *sdw)
|
||||
dais, num_dai);
|
||||
}
|
||||
|
||||
static int intel_start_bus(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
struct sdw_bus *bus = &cdns->bus;
|
||||
int ret;
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* follow recommended programming flows to avoid timeouts when
|
||||
* gsync is enabled
|
||||
*/
|
||||
if (bus->multi_link)
|
||||
sdw_intel_sync_arm(sdw);
|
||||
|
||||
ret = sdw_cdns_init(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_exit_reset(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (bus->multi_link) {
|
||||
ret = sdw_intel_sync_go(sdw);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
}
|
||||
sdw_cdns_check_self_clearing_bits(cdns, __func__,
|
||||
true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
|
||||
err_interrupt:
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_start_bus_after_reset(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
struct sdw_bus *bus = &cdns->bus;
|
||||
bool clock_stop0;
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* An exception condition occurs for the CLK_STOP_BUS_RESET
|
||||
* case if one or more masters remain active. In this condition,
|
||||
* all the masters are powered on for they are in the same power
|
||||
* domain. Master can preserve its context for clock stop0, so
|
||||
* there is no need to clear slave status and reset bus.
|
||||
*/
|
||||
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
|
||||
|
||||
if (!clock_stop0) {
|
||||
|
||||
/*
|
||||
* make sure all Slaves are tagged as UNATTACHED and
|
||||
* provide reason for reinitialization
|
||||
*/
|
||||
|
||||
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
|
||||
sdw_clear_slave_status(bus, status);
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable interrupts during resume\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* follow recommended programming flows to avoid
|
||||
* timeouts when gsync is enabled
|
||||
*/
|
||||
if (bus->multi_link)
|
||||
sdw_intel_sync_arm(sdw);
|
||||
|
||||
/*
|
||||
* Re-initialize the IP since it was powered-off
|
||||
*/
|
||||
sdw_cdns_init(&sdw->cdns);
|
||||
|
||||
} else {
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable interrupts during resume\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to restart clock during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (!clock_stop0) {
|
||||
ret = sdw_cdns_exit_reset(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to exit bus reset sequence during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (bus->multi_link) {
|
||||
ret = sdw_intel_sync_go(sdw);
|
||||
if (ret < 0) {
|
||||
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
}
|
||||
}
|
||||
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
|
||||
err_interrupt:
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void intel_check_clock_stop(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
bool clock_stop0;
|
||||
|
||||
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
|
||||
if (!clock_stop0)
|
||||
dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);
|
||||
}
|
||||
|
||||
static int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
int ret;
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_clock_restart(cdns, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
|
||||
true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
bool wake_enable = false;
|
||||
int ret;
|
||||
|
||||
if (clock_stop) {
|
||||
ret = sdw_cdns_clock_stop(cdns, true);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);
|
||||
else
|
||||
wake_enable = true;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_intel_link_power_down(sdw);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdw_intel_shim_wake(sdw, wake_enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {
|
||||
.debugfs_init = intel_debugfs_init,
|
||||
|
@ -187,4 +187,11 @@ static inline int sdw_intel_sync_go(struct sdw_intel *sdw)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* common bus management */
|
||||
int intel_start_bus(struct sdw_intel *sdw);
|
||||
int intel_start_bus_after_reset(struct sdw_intel *sdw);
|
||||
void intel_check_clock_stop(struct sdw_intel *sdw);
|
||||
int intel_start_bus_after_clock_stop(struct sdw_intel *sdw);
|
||||
int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop);
|
||||
|
||||
#endif /* __SDW_INTEL_LOCAL_H */
|
||||
|
210
drivers/soundwire/intel_bus_common.c
Normal file
210
drivers/soundwire/intel_bus_common.c
Normal file
@ -0,0 +1,210 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
// Copyright(c) 2015-2023 Intel Corporation. All rights reserved.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_intel.h>
|
||||
#include "cadence_master.h"
|
||||
#include "bus.h"
|
||||
#include "intel.h"
|
||||
|
||||
int intel_start_bus(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
struct sdw_bus *bus = &cdns->bus;
|
||||
int ret;
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* follow recommended programming flows to avoid timeouts when
|
||||
* gsync is enabled
|
||||
*/
|
||||
if (bus->multi_link)
|
||||
sdw_intel_sync_arm(sdw);
|
||||
|
||||
ret = sdw_cdns_init(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_exit_reset(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (bus->multi_link) {
|
||||
ret = sdw_intel_sync_go(sdw);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
|
||||
goto err_interrupt;
|
||||
}
|
||||
}
|
||||
sdw_cdns_check_self_clearing_bits(cdns, __func__,
|
||||
true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
|
||||
err_interrupt:
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int intel_start_bus_after_reset(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
struct sdw_bus *bus = &cdns->bus;
|
||||
bool clock_stop0;
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* An exception condition occurs for the CLK_STOP_BUS_RESET
|
||||
* case if one or more masters remain active. In this condition,
|
||||
* all the masters are powered on for they are in the same power
|
||||
* domain. Master can preserve its context for clock stop0, so
|
||||
* there is no need to clear slave status and reset bus.
|
||||
*/
|
||||
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
|
||||
|
||||
if (!clock_stop0) {
|
||||
|
||||
/*
|
||||
* make sure all Slaves are tagged as UNATTACHED and
|
||||
* provide reason for reinitialization
|
||||
*/
|
||||
|
||||
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
|
||||
sdw_clear_slave_status(bus, status);
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable interrupts during resume\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* follow recommended programming flows to avoid
|
||||
* timeouts when gsync is enabled
|
||||
*/
|
||||
if (bus->multi_link)
|
||||
sdw_intel_sync_arm(sdw);
|
||||
|
||||
/*
|
||||
* Re-initialize the IP since it was powered-off
|
||||
*/
|
||||
sdw_cdns_init(&sdw->cdns);
|
||||
|
||||
} else {
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable interrupts during resume\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to restart clock during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (!clock_stop0) {
|
||||
ret = sdw_cdns_exit_reset(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to exit bus reset sequence during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
|
||||
if (bus->multi_link) {
|
||||
ret = sdw_intel_sync_go(sdw);
|
||||
if (ret < 0) {
|
||||
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
|
||||
goto err_interrupt;
|
||||
}
|
||||
}
|
||||
}
|
||||
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
|
||||
err_interrupt:
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void intel_check_clock_stop(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
bool clock_stop0;
|
||||
|
||||
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
|
||||
if (!clock_stop0)
|
||||
dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);
|
||||
}
|
||||
|
||||
int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
int ret;
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_clock_restart(cdns, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
|
||||
sdw_cdns_enable_interrupt(cdns, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
|
||||
true, INTEL_MASTER_RESET_ITERATIONS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
|
||||
{
|
||||
struct device *dev = sdw->cdns.dev;
|
||||
struct sdw_cdns *cdns = &sdw->cdns;
|
||||
bool wake_enable = false;
|
||||
int ret;
|
||||
|
||||
if (clock_stop) {
|
||||
ret = sdw_cdns_clock_stop(cdns, true);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);
|
||||
else
|
||||
wake_enable = true;
|
||||
}
|
||||
|
||||
ret = sdw_cdns_enable_interrupt(cdns, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_intel_link_power_down(sdw);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdw_intel_shim_wake(sdw, wake_enable);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user