Sunday, July 22, 2018

Linux Clock - clk_hw_register_custom_function

note for myself:

Driver clk-stm32h7.c is creating own clock function - clk_register_ready_gate
static struct clk_hw *clk_register_ready_gate(struct device *dev,
  const char *name, const char *parent_name,
  void __iomem *reg, u8 bit_idx, u8 bit_rdy,
  unsigned long flags, spinlock_t *lock)
{
 struct stm32_ready_gate *rgate;
 struct clk_init_data init = { NULL };
 struct clk_hw *hw;
 int ret;

 rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
 if (!rgate)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 init.ops = &ready_gate_clk_ops;
 init.flags = flags;
 init.parent_names = &parent_name;
 init.num_parents = 1;

 rgate->bit_rdy = bit_rdy;
 rgate->gate.lock = lock;
 rgate->gate.reg = reg;
 rgate->gate.bit_idx = bit_idx;
 rgate->gate.hw.init = &init;

 hw = &rgate->gate.hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(rgate);
  hw = ERR_PTR(ret);
 }

 return hw;
}

clk_hw_register is the common function to register clock.

what functions needed to create your own clock function.
static const struct clk_ops
static const struct clk_ops ready_gate_clk_ops = {
 .enable  = ready_gate_clk_enable,
 .disable = ready_gate_clk_disable,
 .is_enabled = clk_gate_is_enabled,
};
enable, disable, is_enabled are needed.

Look at ready_gate_clk_enable
static int ready_gate_clk_enable(struct clk_hw *hw)
{
 struct clk_gate *gate = to_clk_gate(hw);
 struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
 int bit_status;
 unsigned int timeout = RGATE_TIMEOUT;

 if (clk_gate_ops.is_enabled(hw))
  return 0;

 clk_gate_ops.enable(hw);

 /* We can't use readl_poll_timeout() because we can blocked if
  * someone enables this clock before clocksource changes.
  * Only jiffies counter is available. Jiffies are incremented by
  * interruptions and enable op does not allow to be interrupted.
  */
 do {
  bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));

  if (bit_status)
   udelay(100);

 } while (bit_status && --timeout);

 return bit_status;
}

it is checking
1. whether the clock is enabled or not,
2. enable the clock
3. check the register for particular bit, whether the particular bit is ready.

Same goes to ready_gate_clk_disable:
static void ready_gate_clk_disable(struct clk_hw *hw)
{
 struct clk_gate *gate = to_clk_gate(hw);
 struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
 int bit_status;
 unsigned int timeout = RGATE_TIMEOUT;

 if (!clk_gate_ops.is_enabled(hw))
  return;

 clk_gate_ops.disable(hw);

 do {
  bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));

  if (bit_status)
   udelay(100);

 } while (bit_status && --timeout);
}

Almost he same
1. whether the clock is disable or not,
2. disable the clock
3. check the register for particular bit, whether the particular bit is ready.

one thing to take note, in
ready_gate_clk_enable,
ready_gate_clk_disable,
it is using existing "clk_gate_ops.disable(hw);" and "clk_gate_ops.enable(hw);" to disable and enable clock.
However it is adding a layer of checking to check whether the clock is ready or not.

Erm, now, where does "clk_register_ready_gate" is used.

 hws[HSE_CK] = clk_register_ready_gate(NULL,
    "hse_ck",
    hse_clk,
    RCC_CR + base,
    16, 17,
    0,
    &stm32rcc_lock);

 hws[LSE_CK] = clk_register_ready_gate(NULL,
    "lse_ck",
    lse_clk,
    RCC_BDCR + base,
    0, 1,
    0,
    &stm32rcc_lock);

Go read databook for RCC_CR and RCC_BDCR.
RCC_CR:
Bit 17 HSERDY: HSE clock ready flag
0: HSE clock is not ready (default after reset)
1: HSE clock is ready
Bit 16 HSEON: HSE clock enable
0: HSE is OFF (default after reset)
1: HSE is ON

RCC_BDCR:
Bit 1 LSERDY: LSE oscillator ready
0: LSE oscillator not ready (default after backup domain reset)
1: LSE oscillator ready
Bit 0 LSEON: LSE oscillator enabled
0: LSE oscillator OFF (default after backup domain reset)
1: LSE oscillator ON

From here, we know that this function "clk_register_ready_gate" still performing normal clock gating using default gate-clock framework, but it is adding a wait function to allow the clock to stabilize. After the clock is stabilized, it is indicated by ready_bit.

ah.., I couldnt understand the code without databook.
Most drivers at linux mainline doesnt provide databook to public.
So I am thankful to have MCU manufacturer to open out the databook.
STM is the one to thank in this case. Thank you.

No comments:

Post a Comment