]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
clk: divider: Introduce CLK_DIVIDER_EVEN_INTEGERS flag
authorThéo Lebrun <theo.lebrun@bootlin.com>
Mon, 7 Oct 2024 13:49:18 +0000 (15:49 +0200)
committerStephen Boyd <sboyd@kernel.org>
Thu, 17 Oct 2024 18:16:01 +0000 (11:16 -0700)
Add CLK_DIVIDER_EVEN_INTEGERS flag to support divisor of 2, 4, 6, etc.
The same divisor can be done using a table, which would be big and
wasteful for a clock dividor of width 8 (256 entries).

Require increasing flags size from u8 to u16 because
CLK_DIVIDER_EVEN_INTEGERS is the eighth flag. u16 is used inside struct
clk_divider; `unsigned long` is used for function arguments.

Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
Link: https://lore.kernel.org/r/20241007-mbly-clk-v5-3-e9d8994269cb@bootlin.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/clk-divider.c
include/linux/clk-provider.h

index a2c2b5203b0a95cf1cf651b1fb4e2c24d230d831..c1f426b8a5043cb5a1de08e1da385928ec54a2ed 100644 (file)
@@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
                return clk_div_mask(width);
        if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return 1 << clk_div_mask(width);
+       if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+               return 2 * (clk_div_mask(width) + 1);
        if (table)
                return _get_table_maxdiv(table, width);
        return clk_div_mask(width) + 1;
@@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table,
                return 1 << val;
        if (flags & CLK_DIVIDER_MAX_AT_ZERO)
                return val ? val : clk_div_mask(width) + 1;
+       if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+               return 2 * (val + 1);
        if (table)
                return _get_table_div(table, val);
        return val + 1;
@@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table,
                return __ffs(div);
        if (flags & CLK_DIVIDER_MAX_AT_ZERO)
                return (div == clk_div_mask(width) + 1) ? 0 : div;
+       if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+               return (div >> 1) - 1;
        if (table)
                return  _get_table_val(table, div);
        return div - 1;
@@ -538,7 +544,8 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
                struct device_node *np, const char *name,
                const char *parent_name, const struct clk_hw *parent_hw,
                const struct clk_parent_data *parent_data, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               void __iomem *reg, u8 shift, u8 width,
+               unsigned long clk_divider_flags,
                const struct clk_div_table *table, spinlock_t *lock)
 {
        struct clk_divider *div;
@@ -610,8 +617,8 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
-               u8 clk_divider_flags, const struct clk_div_table *table,
-               spinlock_t *lock)
+               unsigned long clk_divider_flags,
+               const struct clk_div_table *table, spinlock_t *lock)
 {
        struct clk_hw *hw;
 
@@ -664,7 +671,8 @@ struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
                struct device_node *np, const char *name,
                const char *parent_name, const struct clk_hw *parent_hw,
                const struct clk_parent_data *parent_data, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               void __iomem *reg, u8 shift, u8 width,
+               unsigned long clk_divider_flags,
                const struct clk_div_table *table, spinlock_t *lock)
 {
        struct clk_hw **ptr, *hw;
index 7e43caabb54b901d68484b86c8349febfe12ba0f..dbe793964c24ca3ab3a7facd090dfb6ae9df7631 100644 (file)
@@ -689,13 +689,15 @@ struct clk_div_table {
  * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used
  *     for the divider register.  Setting this flag makes the register accesses
  *     big endian.
+ * CLK_DIVIDER_EVEN_INTEGERS - clock divisor is 2, 4, 6, 8, 10, etc.
+ *     Formula is 2 * (value read from hardware + 1).
  */
 struct clk_divider {
        struct clk_hw   hw;
        void __iomem    *reg;
        u8              shift;
        u8              width;
-       u             flags;
+       u16             flags;
        const struct clk_div_table      *table;
        spinlock_t      *lock;
 };
@@ -711,6 +713,7 @@ struct clk_divider {
 #define CLK_DIVIDER_READ_ONLY          BIT(5)
 #define CLK_DIVIDER_MAX_AT_ZERO                BIT(6)
 #define CLK_DIVIDER_BIG_ENDIAN         BIT(7)
+#define CLK_DIVIDER_EVEN_INTEGERS      BIT(8)
 
 extern const struct clk_ops clk_divider_ops;
 extern const struct clk_ops clk_divider_ro_ops;
@@ -740,19 +743,21 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
                struct device_node *np, const char *name,
                const char *parent_name, const struct clk_hw *parent_hw,
                const struct clk_parent_data *parent_data, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               void __iomem *reg, u8 shift, u8 width,
+               unsigned long clk_divider_flags,
                const struct clk_div_table *table, spinlock_t *lock);
 struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
                struct device_node *np, const char *name,
                const char *parent_name, const struct clk_hw *parent_hw,
                const struct clk_parent_data *parent_data, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               void __iomem *reg, u8 shift, u8 width,
+               unsigned long clk_divider_flags,
                const struct clk_div_table *table, spinlock_t *lock);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
-               u8 clk_divider_flags, const struct clk_div_table *table,
-               spinlock_t *lock);
+               unsigned long clk_divider_flags,
+               const struct clk_div_table *table, spinlock_t *lock);
 /**
  * clk_register_divider - register a divider clock with the clock framework
  * @dev: device registering this clock