From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Sanyog Kale Date: Wed, 16 Aug 2017 12:26:31 +0530 Subject: [PATCH] SoundWire: Perform clock exit by setting clock stop clear As per HW sequence, clock stop clear bit in mcp_control register should be set and wait for bit to be cleared in order to exit Master from clock stop. Hence adding the support. Change-Id: I3491c74a9969e4ce112ed6afc5eb366e1cc6737a Signed-off-by: Sanyog Kale Signed-off-by: Paul, Subhankar --- drivers/sdw/sdw_cnl.c | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/sdw/sdw_cnl.c b/drivers/sdw/sdw_cnl.c index 95eb7a8fab2b..c754edbe6564 100644 --- a/drivers/sdw/sdw_cnl.c +++ b/drivers/sdw/sdw_cnl.c @@ -485,7 +485,7 @@ static int sdw_init(struct cnl_sdw *sdw, bool is_first_init) int mcp_config, mcp_control, sync_reg, mcp_clockctrl; volatile int sync_update = 0; int timeout = 10; /* Try 10 times before timing out */ - int ret = 0; + int ret = 0, mask; /* Power up the link controller */ ret = sdw_power_up_link(sdw); @@ -498,6 +498,56 @@ static int sdw_init(struct cnl_sdw *sdw, bool is_first_init) /* Switch the ownership to Master IP from glue logic */ sdw_switch_to_mip(sdw); + /* write to MCP Control register to enable block wakeup */ + mcp_control = cnl_sdw_reg_readl(data->sdw_regs, SDW_CNL_MCP_CONTROL); + mask = (MCP_CONTROL_BLOCKWAKEUP_MASK << + MCP_CONTROL_BLOCKWAKEUP_SHIFT); + mcp_control &= ~mask; + cnl_sdw_reg_writel(data->sdw_regs, SDW_CNL_MCP_CONTROL, mcp_control); + do { + mcp_control = cnl_sdw_reg_readl(data->sdw_regs, + SDW_CNL_MCP_CONTROL); + if (!(mcp_control & mask)) + break; + + timeout--; + /* Wait 20ms before each time */ + msleep(20); + } while (timeout != 0); + + /* Write the MCP Control register to exit from clock stop */ + mcp_control = cnl_sdw_reg_readl(data->sdw_regs, SDW_CNL_MCP_CONTROL); + mask = (MCP_CONTROL_CLOCKSTOPCLEAR_MASK << + MCP_CONTROL_CLOCKSTOPCLEAR_SHIFT); + mcp_control |= mask; + cnl_sdw_reg_writel(data->sdw_regs, SDW_CNL_MCP_CONTROL, mcp_control); + + /* Reset timeout */ + timeout = 10; + + /* Wait for clock stop exit bit to be self cleared */ + do { + mcp_control = cnl_sdw_reg_readl(data->sdw_regs, + SDW_CNL_MCP_CONTROL); + if (!(mcp_control & mask)) + break; + timeout--; + /* Wait 20ms before each time */ + msleep(20); + } while (timeout != 0); + + /* Read once again to confirm */ + mcp_control = cnl_sdw_reg_readl(data->sdw_regs, SDW_CNL_MCP_CONTROL); + if (!(mcp_control & mask)) { + dev_dbg(&sdw->mstr->dev, "SDW ctrl %d exit clock stop success\n", + data->inst_id); + } else { + dev_err(&sdw->mstr->dev, + "Failed exit from clock stop SDW ctrl %d\n", + data->inst_id); + return -EIO; + } + /* Set SyncPRD period */ sync_reg = cnl_sdw_reg_readl(data->sdw_shim, SDW_CNL_SYNC); sync_reg |= (SDW_CNL_DEFAULT_SYNC_PERIOD << CNL_SYNC_SYNCPRD_SHIFT); @@ -506,6 +556,9 @@ static int sdw_init(struct cnl_sdw *sdw, bool is_first_init) sync_reg |= (0x1 << CNL_SYNC_SYNCCPU_SHIFT); cnl_sdw_reg_writel(data->sdw_shim, SDW_CNL_SYNC, sync_reg); + /* Reset timeout */ + timeout = 10; + do { sync_update = cnl_sdw_reg_readl(data->sdw_shim, SDW_CNL_SYNC); if ((sync_update & CNL_SYNC_SYNCCPU_MASK) == 0) -- https://clearlinux.org