diff --git a/drivers/soc/qcom/llcc_perfmon.c b/drivers/soc/qcom/llcc_perfmon.c index 99278c99cc31..f1794e906351 100644 --- a/drivers/soc/qcom/llcc_perfmon.c +++ b/drivers/soc/qcom/llcc_perfmon.c @@ -69,6 +69,7 @@ struct event_port_ops { * @expires: timer expire time in nano seconds * @num_mc: number of MCS * @version: Version information of llcc block + * @clk: clock node to enable qdss */ struct llcc_perfmon_private { struct regmap *llcc_map; @@ -86,6 +87,7 @@ struct llcc_perfmon_private { ktime_t expires; unsigned int num_mc; unsigned int version; + struct clk *clock; }; static inline void llcc_bcast_write(struct llcc_perfmon_private *llcc_priv, @@ -500,6 +502,7 @@ static ssize_t perfmon_start_store(struct device *dev, struct llcc_perfmon_private *llcc_priv = dev_get_drvdata(dev); uint32_t val = 0, mask_val; unsigned long start; + int ret; if (kstrtoul(buf, 0, &start)) return -EINVAL; @@ -512,6 +515,12 @@ static ssize_t perfmon_start_store(struct device *dev, return -EINVAL; } + ret = clk_prepare_enable(llcc_priv->clock); + if (ret) { + mutex_unlock(&llcc_priv->mutex); + return -EINVAL; + } + val = MANUAL_MODE | MONITOR_EN; if (llcc_priv->expires) { if (hrtimer_is_queued(&llcc_priv->hrtimer)) @@ -534,6 +543,10 @@ static ssize_t perfmon_start_store(struct device *dev, mask_val = PERFMON_MODE_MONITOR_MODE_MASK | PERFMON_MODE_MONITOR_EN_MASK; llcc_bcast_modify(llcc_priv, PERFMON_MODE, val, mask_val); + + if (!start) + clk_disable_unprepare(llcc_priv->clock); + mutex_unlock(&llcc_priv->mutex); return count; } @@ -1269,6 +1282,12 @@ static int llcc_perfmon_probe(struct platform_device *pdev) else if (val == LLCC_VERSION_2) llcc_priv->version = REV_2; + llcc_priv->clock = devm_clk_get(pdev->dev.parent, "qdss_clk"); + if (IS_ERR_OR_NULL(llcc_priv->clock)) { + pr_err("failed to get clock node\n"); + return PTR_ERR(llcc_priv->clock); + } + result = sysfs_create_group(&pdev->dev.kobj, &llcc_perfmon_group); if (result) { pr_err("Unable to create sysfs group\n");