unsigned long           max_rate;
        unsigned long           accuracy;
        int                     phase;
+       struct clk_duty         duty;
        struct hlist_head       children;
        struct hlist_node       child_node;
        struct hlist_head       clks;
 }
 EXPORT_SYMBOL_GPL(clk_get_phase);
 
+static void clk_core_reset_duty_cycle_nolock(struct clk_core *core)
+{
+       /* Assume a default value of 50% */
+       core->duty.num = 1;
+       core->duty.den = 2;
+}
+
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core);
+
+static int clk_core_update_duty_cycle_nolock(struct clk_core *core)
+{
+       struct clk_duty *duty = &core->duty;
+       int ret = 0;
+
+       if (!core->ops->get_duty_cycle)
+               return clk_core_update_duty_cycle_parent_nolock(core);
+
+       ret = core->ops->get_duty_cycle(core->hw, duty);
+       if (ret)
+               goto reset;
+
+       /* Don't trust the clock provider too much */
+       if (duty->den == 0 || duty->num > duty->den) {
+               ret = -EINVAL;
+               goto reset;
+       }
+
+       return 0;
+
+reset:
+       clk_core_reset_duty_cycle_nolock(core);
+       return ret;
+}
+
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core)
+{
+       int ret = 0;
+
+       if (core->parent &&
+           core->flags & CLK_DUTY_CYCLE_PARENT) {
+               ret = clk_core_update_duty_cycle_nolock(core->parent);
+               memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
+       } else {
+               clk_core_reset_duty_cycle_nolock(core);
+       }
+
+       return ret;
+}
+
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
+                                                struct clk_duty *duty);
+
+static int clk_core_set_duty_cycle_nolock(struct clk_core *core,
+                                         struct clk_duty *duty)
+{
+       int ret;
+
+       lockdep_assert_held(&prepare_lock);
+
+       if (clk_core_rate_is_protected(core))
+               return -EBUSY;
+
+       trace_clk_set_duty_cycle(core, duty);
+
+       if (!core->ops->set_duty_cycle)
+               return clk_core_set_duty_cycle_parent_nolock(core, duty);
+
+       ret = core->ops->set_duty_cycle(core->hw, duty);
+       if (!ret)
+               memcpy(&core->duty, duty, sizeof(*duty));
+
+       trace_clk_set_duty_cycle_complete(core, duty);
+
+       return ret;
+}
+
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
+                                                struct clk_duty *duty)
+{
+       int ret = 0;
+
+       if (core->parent &&
+           core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) {
+               ret = clk_core_set_duty_cycle_nolock(core->parent, duty);
+               memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
+       }
+
+       return ret;
+}
+
+/**
+ * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @num: numerator of the duty cycle ratio to be applied
+ * @den: denominator of the duty cycle ratio to be applied
+ *
+ * Apply the duty cycle ratio if the ratio is valid and the clock can
+ * perform this operation
+ *
+ * Returns (0) on success, a negative errno otherwise.
+ */
+int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den)
+{
+       int ret;
+       struct clk_duty duty;
+
+       if (!clk)
+               return 0;
+
+       /* sanity check the ratio */
+       if (den == 0 || num > den)
+               return -EINVAL;
+
+       duty.num = num;
+       duty.den = den;
+
+       clk_prepare_lock();
+
+       if (clk->exclusive_count)
+               clk_core_rate_unprotect(clk->core);
+
+       ret = clk_core_set_duty_cycle_nolock(clk->core, &duty);
+
+       if (clk->exclusive_count)
+               clk_core_rate_protect(clk->core);
+
+       clk_prepare_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_duty_cycle);
+
+static int clk_core_get_scaled_duty_cycle(struct clk_core *core,
+                                         unsigned int scale)
+{
+       struct clk_duty *duty = &core->duty;
+       int ret;
+
+       clk_prepare_lock();
+
+       ret = clk_core_update_duty_cycle_nolock(core);
+       if (!ret)
+               ret = mult_frac(scale, duty->num, duty->den);
+
+       clk_prepare_unlock();
+
+       return ret;
+}
+
+/**
+ * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
+ * @clk: clock signal source
+ * @scale: scaling factor to be applied to represent the ratio as an integer
+ *
+ * Returns the duty cycle ratio of a clock node multiplied by the provided
+ * scaling factor, or negative errno on error.
+ */
+int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale)
+{
+       if (!clk)
+               return 0;
+
+       return clk_core_get_scaled_duty_cycle(clk->core, scale);
+}
+EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle);
+
 /**
  * clk_is_match - check if two clk's point to the same hardware clock
  * @p: clk compared against q
        if (!c)
                return;
 
-       seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
+       seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
                   level * 3 + 1, "",
                   30 - level * 3, c->name,
                   c->enable_count, c->prepare_count, c->protect_count,
                   clk_core_get_rate(c), clk_core_get_accuracy(c),
-                  clk_core_get_phase(c));
+                  clk_core_get_phase(c),
+                  clk_core_get_scaled_duty_cycle(c, 100000));
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
        struct clk_core *c;
        struct hlist_head **lists = (struct hlist_head **)s->private;
 
-       seq_puts(s, "                                 enable  prepare  protect                               \n");
-       seq_puts(s, "   clock                          count    count    count        rate   accuracy   phase\n");
-       seq_puts(s, "----------------------------------------------------------------------------------------\n");
+       seq_puts(s, "                                 enable  prepare  protect                                duty\n");
+       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle\n");
+       seq_puts(s, "---------------------------------------------------------------------------------------------\n");
 
        clk_prepare_lock();
 
        seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
        seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
        seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
+       seq_printf(s, "\"duty_cycle\": %u",
+                  clk_core_get_scaled_duty_cycle(c, 100000));
 }
 
 static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
        ENTRY(CLK_SET_RATE_UNGATE),
        ENTRY(CLK_IS_CRITICAL),
        ENTRY(CLK_OPS_PARENT_ENABLE),
+       ENTRY(CLK_DUTY_CYCLE_PARENT),
 #undef ENTRY
 };
 
 }
 DEFINE_SHOW_ATTRIBUTE(possible_parents);
 
+static int clk_duty_cycle_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+       struct clk_duty *duty = &core->duty;
+
+       seq_printf(s, "%u/%u\n", duty->num, duty->den);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);
+
 static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
 {
        struct dentry *root;
        debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
        debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
        debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
+       debugfs_create_file("clk_duty_cycle", 0444, root, core,
+                           &clk_duty_cycle_fops);
 
        if (core->num_parents > 1)
                debugfs_create_file("clk_possible_parents", 0444, root, core,
        else
                core->phase = 0;
 
+       /*
+        * Set clk's duty cycle.
+        */
+       clk_core_update_duty_cycle_nolock(core);
+
        /*
         * Set clk's rate.  The preferred method is to use .recalc_rate.  For
         * simple clocks and lazy developers the default fallback is to use the
 
 #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
 /* parents need enable during gate/ungate, set rate and re-parent */
 #define CLK_OPS_PARENT_ENABLE  BIT(12)
+/* duty cycle call may be forwarded to the parent clock */
+#define CLK_DUTY_CYCLE_PARENT  BIT(13)
 
 struct clk;
 struct clk_hw;
        struct clk_hw *best_parent_hw;
 };
 
+/**
+ * struct clk_duty - Struture encoding the duty cycle ratio of a clock
+ *
+ * @num:       Numerator of the duty cycle ratio
+ * @den:       Denominator of the duty cycle ratio
+ */
+struct clk_duty {
+       unsigned int num;
+       unsigned int den;
+};
+
 /**
  * struct clk_ops -  Callback operations for hardware clocks; these are to
  * be provided by the clock implementation, and will be called by drivers
  *             by the second argument. Valid values for degrees are
  *             0-359. Return 0 on success, otherwise -EERROR.
  *
+ * @get_duty_cycle: Queries the hardware to get the current duty cycle ratio
+ *              of a clock. Returned values denominator cannot be 0 and must be
+ *              superior or equal to the numerator.
+ *
+ * @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by
+ *              the numerator (2nd argurment) and denominator (3rd  argument).
+ *              Argument must be a valid ratio (denominator > 0
+ *              and >= numerator) Return 0 on success, otherwise -EERROR.
+ *
  * @init:      Perform platform-specific initialization magic.
  *             This is not not used by any of the basic clock types.
  *             Please consider other ways of solving initialization problems
                                           unsigned long parent_accuracy);
        int             (*get_phase)(struct clk_hw *hw);
        int             (*set_phase)(struct clk_hw *hw, int degrees);
+       int             (*get_duty_cycle)(struct clk_hw *hw,
+                                         struct clk_duty *duty);
+       int             (*set_duty_cycle)(struct clk_hw *hw,
+                                         struct clk_duty *duty);
        void            (*init)(struct clk_hw *hw);
        void            (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
 };