|
@@ -154,3 +154,197 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
|
|
* the clock may have been made this way by choice.
|
|
|
*/
|
|
|
|
|
|
+ WARN_ON(clk->ops == NULL);
|
|
|
+ WARN_ON(clk->ops && clk->ops->set_rate == NULL);
|
|
|
+
|
|
|
+ if (clk->ops == NULL || clk->ops->set_rate == NULL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&clocks_lock, flags);
|
|
|
+ ret = (clk->ops->set_rate)(clk, rate);
|
|
|
+ spin_unlock_irqrestore(&clocks_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+struct clk *clk_get_parent(struct clk *clk)
|
|
|
+{
|
|
|
+ return clk->parent;
|
|
|
+}
|
|
|
+
|
|
|
+int clk_set_parent(struct clk *clk, struct clk *parent)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(parent))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&clocks_lock, flags);
|
|
|
+
|
|
|
+ if (clk->ops && clk->ops->set_parent)
|
|
|
+ ret = (clk->ops->set_parent)(clk, parent);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&clocks_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(clk_enable);
|
|
|
+EXPORT_SYMBOL(clk_disable);
|
|
|
+EXPORT_SYMBOL(clk_get_rate);
|
|
|
+EXPORT_SYMBOL(clk_round_rate);
|
|
|
+EXPORT_SYMBOL(clk_set_rate);
|
|
|
+EXPORT_SYMBOL(clk_get_parent);
|
|
|
+EXPORT_SYMBOL(clk_set_parent);
|
|
|
+
|
|
|
+/* base clocks */
|
|
|
+
|
|
|
+int clk_default_setrate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ clk->rate = rate;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+struct clk_ops clk_ops_def_setrate = {
|
|
|
+ .set_rate = clk_default_setrate,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_xtal = {
|
|
|
+ .name = "xtal",
|
|
|
+ .rate = 0,
|
|
|
+ .parent = NULL,
|
|
|
+ .ctrlbit = 0,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_ext = {
|
|
|
+ .name = "ext",
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_epll = {
|
|
|
+ .name = "epll",
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_mpll = {
|
|
|
+ .name = "mpll",
|
|
|
+ .ops = &clk_ops_def_setrate,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_upll = {
|
|
|
+ .name = "upll",
|
|
|
+ .parent = NULL,
|
|
|
+ .ctrlbit = 0,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_f = {
|
|
|
+ .name = "fclk",
|
|
|
+ .rate = 0,
|
|
|
+ .parent = &clk_mpll,
|
|
|
+ .ctrlbit = 0,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_h = {
|
|
|
+ .name = "hclk",
|
|
|
+ .rate = 0,
|
|
|
+ .parent = NULL,
|
|
|
+ .ctrlbit = 0,
|
|
|
+ .ops = &clk_ops_def_setrate,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_p = {
|
|
|
+ .name = "pclk",
|
|
|
+ .rate = 0,
|
|
|
+ .parent = NULL,
|
|
|
+ .ctrlbit = 0,
|
|
|
+ .ops = &clk_ops_def_setrate,
|
|
|
+};
|
|
|
+
|
|
|
+struct clk clk_usb_bus = {
|
|
|
+ .name = "usb-bus",
|
|
|
+ .rate = 0,
|
|
|
+ .parent = &clk_upll,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+struct clk s3c24xx_uclk = {
|
|
|
+ .name = "uclk",
|
|
|
+};
|
|
|
+
|
|
|
+/* initialise the clock system */
|
|
|
+
|
|
|
+/**
|
|
|
+ * s3c24xx_register_clock() - register a clock
|
|
|
+ * @clk: The clock to register
|
|
|
+ *
|
|
|
+ * Add the specified clock to the list of clocks known by the system.
|
|
|
+ */
|
|
|
+int s3c24xx_register_clock(struct clk *clk)
|
|
|
+{
|
|
|
+ if (clk->enable == NULL)
|
|
|
+ clk->enable = clk_null_enable;
|
|
|
+
|
|
|
+ /* fill up the clk_lookup structure and register it*/
|
|
|
+ clk->lookup.dev_id = clk->devname;
|
|
|
+ clk->lookup.con_id = clk->name;
|
|
|
+ clk->lookup.clk = clk;
|
|
|
+ clkdev_add(&clk->lookup);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * s3c24xx_register_clocks() - register an array of clock pointers
|
|
|
+ * @clks: Pointer to an array of struct clk pointers
|
|
|
+ * @nr_clks: The number of clocks in the @clks array.
|
|
|
+ *
|
|
|
+ * Call s3c24xx_register_clock() for all the clock pointers contained
|
|
|
+ * in the @clks list. Returns the number of failures.
|
|
|
+ */
|
|
|
+int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
|
|
|
+{
|
|
|
+ int fails = 0;
|
|
|
+
|
|
|
+ for (; nr_clks > 0; nr_clks--, clks++) {
|
|
|
+ if (s3c24xx_register_clock(*clks) < 0) {
|
|
|
+ struct clk *clk = *clks;
|
|
|
+ printk(KERN_ERR "%s: failed to register %p: %s\n",
|
|
|
+ __func__, clk, clk->name);
|
|
|
+ fails++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return fails;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * s3c_register_clocks() - register an array of clocks
|
|
|
+ * @clkp: Pointer to the first clock in the array.
|
|
|
+ * @nr_clks: Number of clocks to register.
|
|
|
+ *
|
|
|
+ * Call s3c24xx_register_clock() on the @clkp array given, printing an
|
|
|
+ * error if it fails to register the clock (unlikely).
|
|
|
+ */
|
|
|
+void __init s3c_register_clocks(struct clk *clkp, int nr_clks)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ for (; nr_clks > 0; nr_clks--, clkp++) {
|
|
|
+ ret = s3c24xx_register_clock(clkp);
|
|
|
+
|
|
|
+ if (ret < 0) {
|
|
|
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
|
|
|
+ clkp->name, ret);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * s3c_disable_clocks() - disable an array of clocks
|
|
|
+ * @clkp: Pointer to the first clock in the array.
|
|
|
+ * @nr_clks: Number of clocks to register.
|
|
|
+ *
|
|
|
+ * for internal use only at initialisation time. disable the clocks in the
|
|
|
+ * @clkp array.
|
|
|
+ */
|
|
|
+
|
|
|
+void __init s3c_disable_clocks(struct clk *clkp, int nr_clks)
|