clk: Add support to set custom flags with clk_set_flags

The new API clk_set_flags could be used by hardware specific clock drivers
or clients for specific hardware requirements. These flags could be custom
defined as per hardware needs.

Change-Id: Ia67373ee2b8934c898052c68338fa86cb16070dd
Signed-off-by: Taniya Das <tdas@codeaurora.org>
Signed-off-by: Deepak Katragadda <dkatraga@codeaurora.org>
Signed-off-by: David Dai <daidavid1@codeaurora.org>
This commit is contained in:
David Dai
2016-06-15 12:15:01 +05:30
committed by Gerrit - the friendly Code Review server
parent 72969e942f
commit b904878a04
6 changed files with 94 additions and 2 deletions

View File

@@ -2604,6 +2604,18 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
}
EXPORT_SYMBOL_GPL(clk_is_match);
int clk_set_flags(struct clk *clk, unsigned long flags)
{
if (!clk)
return 0;
if (!clk->core->ops->set_flags)
return -EINVAL;
return clk->core->ops->set_flags(clk->core->hw, flags);
}
EXPORT_SYMBOL_GPL(clk_set_flags);
/*** debugfs support ***/
#ifdef CONFIG_DEBUG_FS

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2013, 2017, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -117,15 +117,62 @@ static int clk_branch_enable(struct clk_hw *hw)
return clk_branch_toggle(hw, true, clk_branch_check_halt);
}
static int clk_cbcr_set_flags(struct regmap *regmap, unsigned int reg,
unsigned long flags)
{
u32 cbcr_val;
regmap_read(regmap, reg, &cbcr_val);
switch (flags) {
case CLKFLAG_PERIPH_OFF_SET:
cbcr_val |= BIT(12);
break;
case CLKFLAG_PERIPH_OFF_CLEAR:
cbcr_val &= ~BIT(12);
break;
case CLKFLAG_RETAIN_PERIPH:
cbcr_val |= BIT(13);
break;
case CLKFLAG_NORETAIN_PERIPH:
cbcr_val &= ~BIT(13);
break;
case CLKFLAG_RETAIN_MEM:
cbcr_val |= BIT(14);
break;
case CLKFLAG_NORETAIN_MEM:
cbcr_val &= ~BIT(14);
break;
default:
return -EINVAL;
}
regmap_write(regmap, reg, cbcr_val);
/* Make sure power is enabled/disabled before returning. */
mb();
udelay(1);
return 0;
}
static void clk_branch_disable(struct clk_hw *hw)
{
clk_branch_toggle(hw, false, clk_branch_check_halt);
}
static int clk_branch_set_flags(struct clk_hw *hw, unsigned int flags)
{
struct clk_branch *br = to_clk_branch(hw);
return clk_cbcr_set_flags(br->clkr.regmap, br->halt_reg, flags);
}
const struct clk_ops clk_branch_ops = {
.enable = clk_branch_enable,
.disable = clk_branch_disable,
.is_enabled = clk_is_enabled_regmap,
.set_flags = clk_branch_set_flags,
};
EXPORT_SYMBOL_GPL(clk_branch_ops);
@@ -143,6 +190,7 @@ const struct clk_ops clk_branch2_ops = {
.enable = clk_branch2_enable,
.disable = clk_branch2_disable,
.is_enabled = clk_is_enabled_regmap,
.set_flags = clk_branch_set_flags,
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2013, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2013, 2017, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_CLK_BRANCH_H__
#define __QCOM_CLK_BRANCH_H__
@@ -44,4 +44,13 @@ extern const struct clk_ops clk_branch_simple_ops;
#define to_clk_branch(_hw) \
container_of(to_clk_regmap(_hw), struct clk_branch, clkr)
enum branch_mem_flags {
CLKFLAG_RETAIN_PERIPH,
CLKFLAG_NORETAIN_PERIPH,
CLKFLAG_RETAIN_MEM,
CLKFLAG_NORETAIN_MEM,
CLKFLAG_PERIPH_OFF_SET,
CLKFLAG_PERIPH_OFF_CLEAR,
};
#endif

View File

@@ -43,10 +43,16 @@ static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw,
return dummy->rrate;
}
static int dummy_clk_set_flags(struct clk_hw *hw, unsigned int flags)
{
return 0;
}
const struct clk_ops clk_dummy_ops = {
.set_rate = dummy_clk_set_rate,
.round_rate = dummy_clk_round_rate,
.recalc_rate = dummy_clk_recalc_rate,
.set_flags = dummy_clk_set_flags,
};
EXPORT_SYMBOL(clk_dummy_ops);

View File

@@ -202,6 +202,8 @@ struct clk_duty {
* directory is provided as an argument. Called with
* prepare_lock held. Returns 0 on success, -EERROR otherwise.
*
* @set_flags: Set custom flags which deal with hardware specifics. Returns 0
* on success, -EERROR otherwise.
*
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
* implementations to split any work between atomic (enable) and sleepable
@@ -246,6 +248,7 @@ struct clk_ops {
struct clk_duty *duty);
void (*init)(struct clk_hw *hw);
void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
int (*set_flags)(struct clk_hw *hw, unsigned int flags);
};
/**

View File

@@ -629,6 +629,15 @@ struct clk *clk_get_parent(struct clk *clk);
*/
struct clk *clk_get_sys(const char *dev_id, const char *con_id);
/**
* clk_set_flags - set the custom HW specific flags for this clock
* @clk: clock source
* @flags: custom flags which would be hardware specific.
*
* Returns success 0 or negative errno.
*/
int clk_set_flags(struct clk *clk, unsigned long flags);
#else /* !CONFIG_HAVE_CLK */
static inline struct clk *clk_get(struct device *dev, const char *id)
@@ -728,6 +737,11 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
return NULL;
}
static inline int clk_set_flags(struct clk *clk, unsigned long flags)
{
return 0;
}
#endif
/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */