summaryrefslogtreecommitdiff
path: root/drivers/clk/rockchip/clk-mmc-phase.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/rockchip/clk-mmc-phase.c')
-rw-r--r--drivers/clk/rockchip/clk-mmc-phase.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index 026a26bb702d..8b1292c56863 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2014 Google, Inc
* Author: Alexandru M Stan <amstan@chromium.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/slab.h>
@@ -18,12 +9,14 @@
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/regmap.h>
#include "clk.h"
struct rockchip_mmc_clock {
struct clk_hw hw;
void __iomem *reg;
- int id;
+ struct regmap *grf;
+ int grf_reg;
int shift;
int cached_phase;
struct notifier_block clk_rate_change_nb;
@@ -55,29 +48,32 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
static int rockchip_mmc_get_phase(struct clk_hw *hw)
{
struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
- unsigned long rate = clk_get_rate(hw->clk);
+ unsigned long rate = clk_hw_get_rate(hw);
u32 raw_value;
u16 degrees;
u32 delay_num = 0;
- /* See the comment for rockchip_mmc_set_phase below */
- if (!rate) {
- pr_err("%s: invalid clk rate\n", __func__);
- return -EINVAL;
- }
+ /* Constant signal, no measurable phase shift */
+ if (!rate)
+ return 0;
+
+ if (mmc_clock->grf)
+ regmap_read(mmc_clock->grf, mmc_clock->grf_reg, &raw_value);
+ else
+ raw_value = readl(mmc_clock->reg);
- raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
+ raw_value >>= mmc_clock->shift;
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
- /* degrees/delaynum * 10000 */
+ /* degrees/delaynum * 1000000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
- 36 * (rate / 1000000);
+ 36 * (rate / 10000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
- degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
+ degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000);
}
return degrees % 360;
@@ -86,7 +82,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
{
struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
- unsigned long rate = clk_get_rate(hw->clk);
+ unsigned long rate = clk_hw_get_rate(hw);
u8 nineties, remainder;
u8 delay_num;
u32 raw_value;
@@ -146,8 +142,12 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
raw_value |= nineties;
- writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift),
- mmc_clock->reg);
+ raw_value = HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift);
+
+ if (mmc_clock->grf)
+ regmap_write(mmc_clock->grf, mmc_clock->grf_reg, raw_value);
+ else
+ writel(raw_value, mmc_clock->reg);
pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
clk_hw_get_name(hw), degrees, delay_num,
@@ -174,11 +174,11 @@ static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb,
/*
* rockchip_mmc_clk is mostly used by mmc controllers to sample
- * the intput data, which expects the fixed phase after the tuning
+ * the input data, which expects the fixed phase after the tuning
* process. However if the clock rate is changed, the phase is stale
* and may break the data sampling. So here we try to restore the phase
* for that case, except that
- * (1) cached_phase is invaild since we inevitably cached it when the
+ * (1) cached_phase is invalid since we inevitably cached it when the
* clock provider be reparented from orphan to its real parent in the
* first place. Otherwise we may mess up the initialization of MMC cards
* since we only set the default sample phase and drive phase later on.
@@ -201,7 +201,9 @@ static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb,
struct clk *rockchip_clk_register_mmc(const char *name,
const char *const *parent_names, u8 num_parents,
- void __iomem *reg, int shift)
+ void __iomem *reg,
+ struct regmap *grf, int grf_reg,
+ int shift)
{
struct clk_init_data init;
struct rockchip_mmc_clock *mmc_clock;
@@ -220,6 +222,8 @@ struct clk *rockchip_clk_register_mmc(const char *name,
mmc_clock->hw.init = &init;
mmc_clock->reg = reg;
+ mmc_clock->grf = grf;
+ mmc_clock->grf_reg = grf_reg;
mmc_clock->shift = shift;
clk = clk_register(NULL, &mmc_clock->hw);