[RESEND v7 14/37] clk: Compatible with narrow registers

Damien Le Moal dlemoal at kernel.org
Fri Apr 5 13:07:04 UTC 2024


On 4/5/24 21:56, Geert Uytterhoeven wrote:
> Hi Sato-san,
> 
> On Thu, Apr 4, 2024 at 7:15 AM Yoshinori Sato
> <ysato at users.sourceforge.jp> wrote:
>> divider and gate only support 32-bit registers.
>> Older hardware uses narrower registers, so I want to be able to handle
>> 8-bit and 16-bit wide registers.
>>
>> Seven clk_divider flags are used, and if I add flags for 8bit access and
>> 16bit access, 8bit will not be enough, so I expanded it to u16.
>>
>> Signed-off-by: Yoshinori Sato <ysato at users.sourceforge.jp>
> 
> Thanks for the update!
> 
>> --- a/drivers/clk/clk-divider.c
>> +++ b/drivers/clk/clk-divider.c
>> @@ -26,20 +26,38 @@
>>   * parent - fixed parent.  No clk_set_parent support
>>   */
>>
>> -static inline u32 clk_div_readl(struct clk_divider *divider)
>> -{
>> -       if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> -               return ioread32be(divider->reg);
>> -
>> -       return readl(divider->reg);
>> +static inline u32 clk_div_read(struct clk_divider *divider)
>> +{
>> +       if (divider->flags & CLK_DIVIDER_REG_8BIT)
> 
> When you need curly braces in one branch of an if/else statement,
> please use curly braces in all branches (everywhere).
> 
>> +               return readb(divider->reg);
>> +       else if (divider->flags & CLK_DIVIDER_REG_16BIT) {

And no need for an else after a return...


>> +               if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> +                       return ioread16be(divider->reg);
>> +               else

and here.

>> +                       return readw(divider->reg);
>> +       } else {
>> +               if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> +                       return ioread32be(divider->reg);
>> +               else

here too.

>> +                       return readl(divider->reg);
>> +       }
>>  }
> 
>> --- a/drivers/clk/clk-gate.c
>> +++ b/drivers/clk/clk-gate.c
> 
>> @@ -137,12 +155,30 @@ struct clk_hw *__clk_hw_register_gate(struct device *dev,
>>         struct clk_init_data init = {};
>>         int ret = -EINVAL;
>>
>> +       /* validate register size option and bit_idx */
>>         if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
>>                 if (bit_idx > 15) {
>>                         pr_err("gate bit exceeds LOWORD field\n");
>>                         return ERR_PTR(-EINVAL);
>>                 }
>>         }
>> +       if (clk_gate_flags & CLK_GATE_REG_16BIT) {
>> +               if (bit_idx > 15) {
>> +                       pr_err("gate bit exceeds 16 bits\n");
>> +                       return ERR_PTR(-EINVAL);
>> +               }
>> +       }
>> +       if (clk_gate_flags & CLK_GATE_REG_8BIT) {
>> +               if (bit_idx > 7) {
>> +                       pr_err("gate bit exceeds 8 bits\n");
>> +                       return ERR_PTR(-EINVAL);
>> +               }
>> +       }
>> +       if ((clk_gate_flags & CLK_GATE_HIWORD_MASK) &&
> 
> If you use parentheses around "a & b" here...
> 
>> +           clk_gate_flags & (CLK_GATE_REG_8BIT | CLK_GATE_REG_16BIT)) {
> 
> please add parentheses here, too.
> 
>> +               pr_err("HIWORD_MASK required 32-bit register\n");
>> +               return ERR_PTR(-EINVAL);
>> +       }
>>
>>         /* allocate the gate */
>>         gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index 4a537260f655..eaa6ff1d0b2e 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -508,12 +508,16 @@ void of_fixed_clk_setup(struct device_node *np);
>>   * CLK_GATE_BIG_ENDIAN - by default little endian register accesses are used for
>>   *     the gate register.  Setting this flag makes the register accesses big
>>   *     endian.
>> + * CLK_GATE_REG_8BIT - by default 32bit register accesses are used for
>> + *     the gate register.  Setting this flag makes the register accesses 8bit.
>> + * CLK_GATE_REG_16BIT - by default 32bit register accesses are used for
>> + *     the gate register.  Setting this flag makes the register accesses 16bit.
>>   */
>>  struct clk_gate {
>>         struct clk_hw hw;
>>         void __iomem    *reg;
>>         u8              bit_idx;
>> -       u8              flags;
>> +       u32             flags;
> 
> (from my comments on v6)
> There is no need to increase the size of the flags field for the gate clock.
> 
> 
>>         spinlock_t      *lock;
>>  };
>>
> 
>> @@ -675,13 +681,17 @@ 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_REG_8BIT - by default 32bit register accesses are used for
>> + *     the gate register.  Setting this flag makes the register accesses 8bit.
>> + * CLK_DIVIDER_REG_16BIT - by default 32bit register accesses are used for
>> + *     the gate register.  Setting this flag makes the register accesses 16bit.
>>   */
>>  struct clk_divider {
>>         struct clk_hw   hw;
>>         void __iomem    *reg;
>>         u8              shift;
>>         u8              width;
>> -       u8              flags;
>> +       u16             flags;
>>         const struct clk_div_table      *table;
>>         spinlock_t      *lock;
>>  };
> 
>> @@ -726,18 +738,18 @@ 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, u32 clk_divider_flags,
> 
> "u16 clk_divider_flags", to match 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, u32 clk_divider_flags,
> 
> Likewise.
> 
>>                 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,
>> +               u32 clk_divider_flags, const struct clk_div_table *table,
> 
> Likewise.
> 
>>                 spinlock_t *lock);
>>  /**
>>   * clk_register_divider - register a divider clock with the clock framework
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 

-- 
Damien Le Moal
Western Digital Research



More information about the dri-devel mailing list