clk: tegra: add locking support to DFLL
Based on part of https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/4f0b1e6e76f7b0ff8d028c66d34da9f37ca39233
This commit is contained in:
1 parent
9642e53c2c
commit
bafa332c10
1 file changed
+25
@@ -359,6 +359,9 @@ struct tegra_dfll {
|
||||
struct pinctrl_state *pwm_enable_state;
|
||||
struct pinctrl_state *pwm_disable_state;
|
||||
u32 reg_init_uV;
|
||||
|
||||
/* spinlock protecting register accesses */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)
|
||||
@@ -1106,6 +1109,7 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
struct dfll_rate_req req;
|
||||
unsigned long flags;
|
||||
|
||||
if (td->mode == DFLL_UNINITIALIZED) {
|
||||
dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n",
|
||||
@@ -1121,8 +1125,10 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
td->last_req = req;
|
||||
|
||||
if (td->mode == DFLL_CLOSED_LOOP) {
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_close_loop_config(td, &td->last_req);
|
||||
dfll_set_frequency_request(td, &td->last_req);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1141,13 +1147,18 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
*/
|
||||
static int dfll_disable(struct tegra_dfll *td)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (td->mode != DFLL_OPEN_LOOP) {
|
||||
dev_err(td->dev, "cannot disable DFLL in %s mode\n",
|
||||
mode_name[td->mode]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_mode(td, DFLL_DISABLED);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
|
||||
pm_runtime_put_sync(td->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1211,6 +1222,7 @@ static void dfll_set_open_loop_config(struct tegra_dfll *td)
|
||||
static int dfll_lock(struct tegra_dfll *td)
|
||||
{
|
||||
struct dfll_rate_req *req = &td->last_req;
|
||||
unsigned long flags;
|
||||
|
||||
switch (td->mode) {
|
||||
case DFLL_CLOSED_LOOP:
|
||||
@@ -1228,10 +1240,12 @@ static int dfll_lock(struct tegra_dfll *td)
|
||||
else
|
||||
dfll_i2c_set_output_enabled(td, true);
|
||||
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_mode(td, DFLL_CLOSED_LOOP);
|
||||
dfll_set_close_loop_config(td, req);
|
||||
dfll_set_frequency_request(td, req);
|
||||
dfll_set_force_output_enabled(td, false);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
@@ -1251,14 +1265,19 @@ static int dfll_lock(struct tegra_dfll *td)
|
||||
*/
|
||||
static int dfll_unlock(struct tegra_dfll *td)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
switch (td->mode) {
|
||||
case DFLL_CLOSED_LOOP:
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_open_loop_config(td);
|
||||
dfll_set_mode(td, DFLL_OPEN_LOOP);
|
||||
if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
|
||||
dfll_pwm_set_output_enabled(td, false);
|
||||
else
|
||||
dfll_i2c_set_output_enabled(td, false);
|
||||
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
return 0;
|
||||
|
||||
case DFLL_OPEN_LOOP:
|
||||
@@ -1521,8 +1540,10 @@ static int attr_registers_show(struct seq_file *s, void *data)
|
||||
{
|
||||
u32 val, offs;
|
||||
struct tegra_dfll *td = s->private;
|
||||
unsigned long flags;
|
||||
|
||||
seq_puts(s, "CONTROL REGISTERS:\n");
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {
|
||||
if (offs == DFLL_OUTPUT_CFG)
|
||||
val = dfll_i2c_readl(td, offs);
|
||||
@@ -1551,6 +1572,8 @@ static int attr_registers_show(struct seq_file *s, void *data)
|
||||
__raw_readl(td->lut_base + offs));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2292,6 +2315,8 @@ int tegra_dfll_register(struct platform_device *pdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&td->lock);
|
||||
|
||||
ret = dfll_register_clk(td);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "DFLL clk registration failed\n");
|
||||
|
||||
Reference in new issue
Block a user