Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 39 additions & 10 deletions drivers/soundwire/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,28 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
mutex_unlock(&bus->bus_lock);
}

static enum sdw_clk_stop_mode sdw_get_clk_stop_mode(struct sdw_slave *slave)
{
struct device *dev = &slave->dev;
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
enum sdw_clk_stop_mode mode;

/*
* Query for clock stop mode if Slave implements
* ops->get_clk_stop_mode, else read from property.
*/
if (drv->ops && drv->ops->get_clk_stop_mode) {
mode = drv->ops->get_clk_stop_mode(slave);
} else {
if (slave->prop.clk_stop_mode1)
mode = SDW_CLK_STOP_MODE1;
else
mode = SDW_CLK_STOP_MODE0;
}

return mode;
}

static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type)
Expand Down Expand Up @@ -1054,6 +1076,7 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num, bo
*/
int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
{
enum sdw_clk_stop_mode mode;
bool simple_clk_stop = true;
struct sdw_slave *slave;
bool is_slave = false;
Expand All @@ -1078,8 +1101,10 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
/* Identify if Slave(s) are available on Bus */
is_slave = true;

ret = sdw_slave_clk_stop_callback(slave,
SDW_CLK_STOP_MODE0,
mode = sdw_get_clk_stop_mode(slave);
slave->curr_clk_stop_mode = mode;

ret = sdw_slave_clk_stop_callback(slave, mode,
SDW_CLK_PRE_PREPARE);
if (ret < 0 && ret != -ENODATA) {
dev_err(&slave->dev, "clock stop pre-prepare cb failed:%d\n", ret);
Expand All @@ -1091,8 +1116,7 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
simple_clk_stop = false;

ret = sdw_slave_clk_stop_prepare(slave,
SDW_CLK_STOP_MODE0,
true);
mode, true);
if (ret < 0 && ret != -ENODATA) {
dev_err(&slave->dev, "clock stop prepare failed:%d\n", ret);
return ret;
Expand Down Expand Up @@ -1129,9 +1153,9 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
if (slave->status != SDW_SLAVE_ATTACHED &&
slave->status != SDW_SLAVE_ALERT)
continue;
mode = slave->curr_clk_stop_mode;

ret = sdw_slave_clk_stop_callback(slave,
SDW_CLK_STOP_MODE0,
ret = sdw_slave_clk_stop_callback(slave, mode,
SDW_CLK_POST_PREPARE);

if (ret < 0 && ret != -ENODATA) {
Expand Down Expand Up @@ -1183,6 +1207,7 @@ EXPORT_SYMBOL(sdw_bus_clk_stop);
*/
int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
{
enum sdw_clk_stop_mode mode;
bool simple_clk_stop = true;
struct sdw_slave *slave;
bool is_slave = false;
Expand All @@ -1204,18 +1229,20 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
/* Identify if Slave(s) are available on Bus */
is_slave = true;

ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
mode = slave->curr_clk_stop_mode;

ret = sdw_slave_clk_stop_callback(slave, mode,
SDW_CLK_PRE_DEPREPARE);
if (ret < 0)
dev_warn(&slave->dev, "clock stop pre-deprepare cb failed:%d\n", ret);


/* Only de-prepare a Slave device if needed */
if (!slave->prop.simple_clk_stop_capable) {
simple_clk_stop = false;

ret = sdw_slave_clk_stop_prepare(slave, SDW_CLK_STOP_MODE0,
ret = sdw_slave_clk_stop_prepare(slave, mode,
false);

if (ret < 0)
dev_warn(&slave->dev, "clock stop deprepare failed:%d\n", ret);
}
Expand Down Expand Up @@ -1243,7 +1270,9 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
slave->status != SDW_SLAVE_ALERT)
continue;

ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
mode = slave->curr_clk_stop_mode;

ret = sdw_slave_clk_stop_callback(slave, mode,
SDW_CLK_POST_DEPREPARE);
if (ret < 0)
dev_warn(&slave->dev, "clock stop post-deprepare cb failed:%d\n", ret);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ struct sdw_slave_ops {
int (*port_prep)(struct sdw_slave *slave,
struct sdw_prepare_ch *prepare_ch,
enum sdw_port_prep_ops pre_ops);
int (*get_clk_stop_mode)(struct sdw_slave *slave);
int (*clk_stop)(struct sdw_slave *slave,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type);
Expand Down Expand Up @@ -676,6 +677,7 @@ struct sdw_slave {
struct list_head node;
struct completion port_ready[SDW_MAX_PORTS];
unsigned int m_port_map[SDW_MAX_PORTS];
enum sdw_clk_stop_mode curr_clk_stop_mode;
u16 dev_num;
u16 dev_num_sticky;
bool probed;
Expand Down
Loading