]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Soundwire: stream: program BUSCLOCK_SCALE
authorBard Liao <yung-chuan.liao@linux.intel.com>
Wed, 18 Dec 2024 08:01:48 +0000 (16:01 +0800)
committerVinod Koul <vkoul@kernel.org>
Mon, 23 Dec 2024 06:30:33 +0000 (12:00 +0530)
We need to program bus clock scale to adjust the bus clock if current
bus clock doesn't fit the bandwidth.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://lore.kernel.org/r/20241218080155.102405-8-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/soundwire/bus.c
drivers/soundwire/stream.c
include/linux/soundwire/sdw.h

index 215630d602adf9c1a8cd6c1651a558e14abb0d62..9b295fc9acd53460af56219ad02712bef3be31e4 100644 (file)
@@ -813,6 +813,16 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
 }
 EXPORT_SYMBOL(sdw_extract_slave_id);
 
+bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave)
+{
+       /*
+        * Dynamic scaling is a defined by SDCA. However, some devices expose the class ID but
+        * can't support dynamic scaling. We might need a quirk to handle such devices.
+        */
+       return slave->id.class_id;
+}
+EXPORT_SYMBOL(is_clock_scaling_supported_by_slave);
+
 static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed)
 {
        u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0};
index 795017c8081a94b78bcad65a7f24514cf3aca1c8..bf04b941012c54395e81cf525636cf269e494ac8 100644 (file)
@@ -629,8 +629,44 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt)
 static int sdw_program_params(struct sdw_bus *bus, bool prepare)
 {
        struct sdw_master_runtime *m_rt;
+       struct sdw_slave *slave;
        int ret = 0;
+       u32 addr1;
+
+       /* Check if all Peripherals comply with SDCA */
+       list_for_each_entry(slave, &bus->slaves, node) {
+               if (!slave->dev_num_sticky)
+                       continue;
+               if (!is_clock_scaling_supported_by_slave(slave)) {
+                       dev_dbg(&slave->dev, "The Peripheral doesn't comply with SDCA\n");
+                       goto manager_runtime;
+               }
+       }
+
+       if (bus->params.next_bank)
+               addr1 = SDW_SCP_BUSCLOCK_SCALE_B1;
+       else
+               addr1 = SDW_SCP_BUSCLOCK_SCALE_B0;
+
+       /* Program SDW_SCP_BUSCLOCK_SCALE if all Peripherals comply with SDCA */
+       list_for_each_entry(slave, &bus->slaves, node) {
+               int scale_index;
+               u8 base;
+
+               if (!slave->dev_num_sticky)
+                       continue;
+               scale_index = sdw_slave_get_scale_index(slave, &base);
+               if (scale_index < 0)
+                       return scale_index;
+
+               ret = sdw_write_no_pm(slave, addr1, scale_index);
+               if (ret < 0) {
+                       dev_err(&slave->dev, "SDW_SCP_BUSCLOCK_SCALE register write failed\n");
+                       return ret;
+               }
+       }
 
+manager_runtime:
        list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
 
                /*
index 05a85e2bd96d092cbb93f5ae9ce38d6b3ff89d1b..fc0a203c3ae0e5d1a4aed3002fb8ab653664bfaf 100644 (file)
@@ -1041,6 +1041,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus);
 
 int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
 void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);
+bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave);
 
 #if IS_ENABLED(CONFIG_SOUNDWIRE)