This patch expands the regmap support to allow registration of clock
dividers. It just prepares for the introduction of a clkdiv driver,
that will be in a separate patch.
Such dividers are found in the Qualcomm PMIC chips such as PM8941,
PMA8084 and others.

Signed-off-by: Georgi Djakov <gdja...@mm-sol.com>
---
 drivers/clk/qcom/clk-regmap.c |   68 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/qcom/clk-regmap.h |   24 +++++++++++++++
 2 files changed, 92 insertions(+)

diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c
index a58ba39..d63b8ca 100644
--- a/drivers/clk/qcom/clk-regmap.c
+++ b/drivers/clk/qcom/clk-regmap.c
@@ -112,3 +112,71 @@ struct clk *devm_clk_register_regmap(struct device *dev,
        return devm_clk_register(dev, &rclk->hw);
 }
 EXPORT_SYMBOL_GPL(devm_clk_register_regmap);
+
+/**
+ * clkdiv_recalc_rate_regmap - Calculate clock divider output rate
+ */
+unsigned long clkdiv_recalc_rate_regmap(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct clk_regmap *rclk = to_clk_regmap(hw);
+       struct clkdiv_regmap *clkdiv = to_clkdiv_regmap(rclk);
+       unsigned int div, val;
+
+       regmap_read(rclk->regmap, clkdiv->reg, &val);
+       if (!val)
+               return parent_rate;
+
+       div = (val >> clkdiv->shift) & ((1 << clkdiv->width)-1);
+
+       return parent_rate / div;
+}
+EXPORT_SYMBOL_GPL(clkdiv_recalc_rate_regmap);
+
+static const struct clk_ops clkdiv_ops = {
+       .enable = clk_enable_regmap,
+       .disable = clk_disable_regmap,
+       .is_enabled = clk_is_enabled_regmap,
+       .recalc_rate = clkdiv_recalc_rate_regmap,
+};
+EXPORT_SYMBOL_GPL(clkdiv_ops);
+
+/**
+ * devm_clkdiv_register_regmap - register a clk_regmap clock divider
+ *
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @clkdiv: clock divider to operate on
+ *
+ * Clocks that use regmap for their register I/O should register their
+ * clk_regmap struct via this function so that the regmap is initialized
+ * and so that the clock is registered with the common clock framework.
+ */
+struct clk *devm_clkdiv_register_regmap(struct device *dev, const char *name,
+                                       const char *parent_name,
+                                       unsigned long flags,
+                                       struct clkdiv_regmap *clkdiv)
+{
+       struct clk_init_data init;
+
+       if (!clkdiv)
+               return ERR_PTR(-ENODEV);
+
+       clkdiv->rclk.regmap = dev_get_regmap(dev->parent, NULL);
+
+       if (!clkdiv->rclk.regmap)
+               return ERR_PTR(-ENXIO);
+
+       init.name = name;
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+       init.flags = flags;
+       init.ops = &clkdiv_ops;
+
+       clkdiv->rclk.hw.init = &init;
+
+       return devm_clk_register(dev, &clkdiv->rclk.hw);
+}
+EXPORT_SYMBOL_GPL(devm_clkdiv_register_regmap);
diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h
index 491a63d..02582cf 100644
--- a/drivers/clk/qcom/clk-regmap.h
+++ b/drivers/clk/qcom/clk-regmap.h
@@ -42,4 +42,28 @@ void clk_disable_regmap(struct clk_hw *hw);
 struct clk *
 devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk);
 
+/**
+ * struct clkdiv_regmap - regmap supporting clock divider
+ * @rclk:   regmap supporting clock struct
+ * @reg:    offset into regmap for the control register
+ * @shift:  bit position for divider value
+ * @width:  number of bits used for divider value
+ * @table:  pointer to table containing an array of divider/value pairs
+ */
+struct clkdiv_regmap {
+       struct clk_regmap rclk;
+       unsigned int reg;
+       unsigned int shift;
+       unsigned int width;
+       struct clk_div_table *table;
+};
+
+#define to_clkdiv_regmap(_rclk) container_of(_rclk, struct clkdiv_regmap, rclk)
+
+unsigned long
+clkdiv_recalc_rate_regmap(struct clk_hw *hw, unsigned long parent_rate);
+struct clk *
+devm_clkdiv_register_regmap(struct device *dev, const char *name,
+                           const char *parent_name, unsigned long flags,
+                           struct clkdiv_regmap *clkdiv);
 #endif
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to