/** * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering * from HSDivider PWRDN problem Implements Errata ID: i556. * @clk: DPLL output struct clk * * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset * valueafter their respective PWRDN bits are set. Any dummy write * (Any other value different from the Read value) to the * corresponding CM_CLKSEL register will refresh the dividers. */ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *hw) { struct clk_divider *parent; struct clk_hw *parent_hw; u32 dummy_v, orig_v; int ret; /* Clear PWRDN bit of HSDIVIDER */ ret = omap2_dflt_clk_enable(hw); /* Parent is the x2 node, get parent of parent for the m2 div */ parent_hw = clk_hw_get_parent(clk_hw_get_parent(hw)); parent = to_clk_divider(parent_hw); /* Restore the dividers */ if (!ret) { orig_v = ti_clk_ll_ops->clk_readl(parent->reg); dummy_v = orig_v; /* Write any other value different from the Read value */ dummy_v ^= (1 << parent->shift); ti_clk_ll_ops->clk_writel(dummy_v, parent->reg); /* Write the original divider */ ti_clk_ll_ops->clk_writel(orig_v, parent->reg); } return ret; }
/** * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering * from HSDivider PWRDN problem Implements Errata ID: i556. * @clk: DPLL output struct clk * * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset * valueafter their respective PWRDN bits are set. Any dummy write * (Any other value different from the Read value) to the * corresponding CM_CLKSEL register will refresh the dividers. */ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) { struct clk_divider *parent; struct clk_hw *parent_hw; u32 dummy_v, orig_v; struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk); int ret; /* Clear PWRDN bit of HSDIVIDER */ ret = omap2_dflt_clk_enable(clk); parent_hw = __clk_get_hw(__clk_get_parent(clk->clk)); parent = to_clk_divider(parent_hw); /* Restore the dividers */ if (!ret) { orig_v = omap2_clk_readl(omap_clk, parent->reg); dummy_v = orig_v; /* Write any other value different from the Read value */ dummy_v ^= (1 << parent->shift); omap2_clk_writel(dummy_v, omap_clk, parent->reg); /* Write the original divider */ omap2_clk_writel(orig_v, omap_clk, parent->reg); } return ret; }
/** * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering * from HSDivider PWRDN problem Implements Errata ID: i556. * @clk: DPLL output struct clk * * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset * valueafter their respective PWRDN bits are set. Any dummy write * (Any other value different from the Read value) to the * corresponding CM_CLKSEL register will refresh the dividers. */ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) { struct clk_hw_omap *parent; struct clk_hw *parent_hw; u32 dummy_v, orig_v, clksel_shift; int ret; /* Clear PWRDN bit of HSDIVIDER */ ret = omap2_dflt_clk_enable(clk); parent_hw = __clk_get_hw(__clk_get_parent(clk->clk)); parent = to_clk_hw_omap(parent_hw); /* Restore the dividers */ if (!ret) { clksel_shift = __ffs(parent->clksel_mask); orig_v = __raw_readl(parent->clksel_reg); dummy_v = orig_v; /* Write any other value different from the Read value */ dummy_v ^= (1 << clksel_shift); __raw_writel(dummy_v, parent->clksel_reg); /* Write the original divider */ __raw_writel(orig_v, parent->clksel_reg); } return ret; }
/** omap3_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering * from HSDivider problem. * @clk: DPLL output struct clk * * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, dpll4_m5_ck * & dpll4_m6_ck dividers get lost after their respective PWRDN bits are set. * Any write to the corresponding CM_CLKSEL register will refresh the * dividers. Only x2 clocks are affected, so it is safe to trust the parent * clock information to refresh the CM_CLKSEL registers. */ int omap3_pwrdn_clk_enable_with_hsdiv_restore(struct clk *clk) { u32 orig_v, v, c, clksel_shift, max_div; int ret; /* enable the clock */ ret = omap2_dflt_clk_enable(clk); /* Restore the dividers */ if (!ret) { v = __raw_readl(clk->parent->clksel_reg); orig_v = v; clksel_shift = __ffs(clk->parent->clksel_mask); max_div = clk->parent->clksel_mask >> clksel_shift; /* Isolate the current divider */ c = v & clk->parent->clksel_mask; c >>= clksel_shift; /* Prevent excessively high clock rates if divider would wrap */ c += (c == max_div) ? -1 : 1; /* Write the temporarily altered divider back */ c <<= clksel_shift; v &= ~c; v |= c; __raw_writel(v, clk->parent->clksel_reg); /* Write the original divider */ __raw_writel(orig_v, clk->parent->clksel_reg); }
/** * am33xx_dflt_wait_clk_enable() - Enable a am33xx module clock * @clk: Pointer to the clock to be enabled * * This function just wraps omap2_dflt_clk_enable with a check for module idle * status. We loop till module goes to funcitonal state as the immediate access * to module space will not work otherwise. */ int am33xx_dflt_wait_clk_enable(struct clk *clk) { omap2_dflt_clk_enable(clk); omap2_cm_wait_idlest(clk->enable_reg, AM33XX_IDLEST_MASK, AM33XX_IDLEST_VAL, clk->name); return 0; }
int am33xx_sgx_clk_enable(struct clk *clk) { omap2_dflt_clk_enable(clk); /* De-assert local reset after module enable */ omap2_prm_clear_mod_reg_bits(AM33XX_GFX_RST_MASK, AM33XX_PRM_GFX_MOD, AM33XX_RM_GFX_RSTCTRL_OFFSET); omap2_cm_wait_idlest(clk->enable_reg, AM33XX_IDLEST_MASK, AM33XX_IDLEST_VAL, clk->name); return 0; }
static void clkout_clk_disable(struct clk_hw *hw) { omap2_dflt_clk_enable(hw); }
static int clkout_clk_enable(struct clk_hw *hw) { return omap2_dflt_clk_enable(hw); }