soundwire: intel: move bus common sequences to different file
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Tue, 14 Mar 2023 01:54:02 +0000 (09:54 +0800)
committerVinod Koul <vkoul@kernel.org>
Wed, 15 Mar 2023 13:54:02 +0000 (19:24 +0530)
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>
drivers/soundwire/Makefile
drivers/soundwire/intel.c
drivers/soundwire/intel.h
drivers/soundwire/intel_bus_common.c [new file with mode: 0644]

index ca97414..8038e84 100644 (file)
@@ -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
index 8395a20..77d6989 100644 (file)
@@ -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,
index 28b21a9..abd1a50 100644 (file)
@@ -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 */
diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c
new file mode 100644 (file)
index 0000000..9a06ab5
--- /dev/null
@@ -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;
+}