static void sunxi_clk_fators_disable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; if(factor->flags & CLK_IGNORE_DISABLE) return; /* check if the pll disabled already */ reg = factor_readl(factor, factor->reg); if(!GET_BITS(config->enshift, 1, reg)) return; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor, factor->reg); if(config->sdmwidth) reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0); /* update for pll_ddr register */ if(config->updshift) reg = SET_BITS(config->updshift, 1, reg, 1); /* disable pll */ reg = SET_BITS(config->enshift, 1, reg, 0); factor_writel(factor,reg, factor->reg); /* disable pll lock if needed */ sunxi_clk_disable_plllock(factor); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); }
static unsigned long sunxi_clk_factors_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long flags = 0; if(!factor->calc_rate) return 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor,factor->reg); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); if(config->nwidth) factor_val.factorn = GET_BITS(config->nshift, config->nwidth, reg); else factor_val.factorn = 0xffff; if(config->kwidth) factor_val.factork = GET_BITS(config->kshift, config->kwidth, reg); else factor_val.factork = 0xffff; if(config->mwidth) factor_val.factorm = GET_BITS(config->mshift, config->mwidth, reg); else factor_val.factorm = 0xffff; if(config->pwidth) factor_val.factorp = GET_BITS(config->pshift, config->pwidth, reg); else factor_val.factorp = 0xffff; if(config->d1width) factor_val.factord1 = GET_BITS(config->d1shift, config->d1width, reg); else factor_val.factord1 = 0xffff; if(config->d2width) factor_val.factord2 = GET_BITS(config->d2shift, config->d2width, reg); else factor_val.factord2 = 0xffff; if(config->frac) { factor_val.frac_mode = GET_BITS(config->modeshift, 1, reg); factor_val.frac_freq = GET_BITS(config->outshift, 1, reg); } else { factor_val.frac_mode = 0xffff; factor_val.frac_freq = 0xffff; } return factor->calc_rate(parent_rate, &factor_val); }
static int sunxi_clk_fators_is_enabled(struct clk_hw *hw) { unsigned long val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); val = GET_BITS(config->enshift, 1, reg); return val ? 1 : 0; }
static long sunxi_clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_factors_value factor_val; struct sunxi_clk_factors *factor = to_clk_factor(hw); if(!factor->get_factors || !factor->calc_rate) return rate; factor->get_factors(rate, *prate, &factor_val); return factor->calc_rate(*prate, &factor_val); }
static void clk_disable_pll_mipi(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = readl(factor->reg); if(config->sdmwidth) reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0); reg = SET_BITS(config->enshift, 1, reg, 0); reg &= ~(0x3 << 22); writel(reg, factor->reg); }
int set_parent_pll_mipi(struct clk_hw *hw, u8 index) { unsigned long reg; struct sunxi_clk_factors *factor = to_clk_factor(hw); if(!factor->reg) return 0; reg = readl(factor->reg); reg = SET_BITS(21, 1, reg, index); writel(reg, factor->reg); return 0; }
static void sunxi_clk_fators_disable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); if(config->sdmwidth) reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0); reg = SET_BITS(config->enshift, 1, reg, 0); factor_writel(factor,reg, factor->reg); }
u8 get_parent_pll_mipi(struct clk_hw *hw) { u8 parent; unsigned long reg; struct sunxi_clk_factors *factor = to_clk_factor(hw); if(!factor->reg) return 0; reg = readl(factor->reg); parent = GET_BITS(21, 1, reg); return parent; }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } reg = SET_BITS(config->enshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); return 0; }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); unsigned int loop = 300; unsigned long flags = 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } //enable the register reg = SET_BITS(config->enshift, 1, reg, 1); if(config->updshift) //update for pll_ddr register reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); while(loop--) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) break; else udelay(10); } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); if(!loop) #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n",hw->clk->name); #else WARN(1, "clk %s wait lock timeout\n",hw->clk->name); #endif return 0; }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; /* check if the pll enabled already */ reg = factor_readl(factor, factor->reg); if(GET_BITS(config->enshift, 1, reg)) return 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); sunxi_clk_disable_plllock(factor); /* get factor register value */ reg = factor_readl(factor, factor->reg); if(config->sdmwidth) { factor_writel(factor, config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } /* enable the register */ reg = SET_BITS(config->enshift, 1, reg, 1); /* update for pll_ddr register */ if(config->updshift) reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); if (sunxi_clk_is_lock(factor)) { if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_fators_is_enabled(struct clk_hw *hw) { unsigned long val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor,factor->reg); val = GET_BITS(config->enshift, 1, reg); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return val ? 1 : 0; }
static int __init sunxi_clk_default_sdm(void) { #ifdef SYS_CONFIG_PAT_EN struct clk *clk = NULL; script_item_u script_item; struct sunxi_clk_factors *factor=NULL; int i; unsigned long reg; for(i=0;i<sizeof(clkpat_table)/sizeof(struct sunxi_clk_pat_item);i++) { if((script_get_item("clock", clkpat_table[i].patname, &script_item) == SCIRPT_ITEM_VALUE_TYPE_INT)) { clk = clk_get(NULL,clkpat_table[i].name); if(!IS_ERR_OR_NULL(clk)) { factor = to_clk_factor(clk->hw); if(script_item.val) { factor->config->sdmwidth = 1; #ifdef SYS_CONFIG_PAT_VAL if(script_item.val != 1) //avoid old format usage to only enable factor->config->sdmval=script_item.val; #endif //sync with already enable PLLs if (clk->enable_count && __clk_is_enabled(clk)) { reg = readl(factor->reg); writel(factor->config->sdmval, (void __iomem *)factor->config->sdmpat); reg = SET_BITS(factor->config->sdmshift, factor->config->sdmwidth, reg, 1); writel(reg, factor->reg); } } else factor->config->sdmwidth = 0; clk_put(clk); clk=NULL; } } } #endif return 0; }
static int clk_enable_pll_mipi(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = readl(factor->reg); if(config->sdmwidth) { writel(config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } reg |= 0x3 << 22; writel(reg, factor->reg); udelay(100); reg = SET_BITS(config->enshift, 1, reg, 1); writel(reg, factor->reg); udelay(100); return 0; }
static int sunxi_clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long flags = 0; if(!factor->get_factors) return 0; /* factor_val is initialized with its original value, * it's factors(such as:M,N,K,P,d1,d2...) are Random Value. * if donot judge the return value of "factor->get_factors", * it may change the original register value. */ if(factor->get_factors(rate, parent_rate, &factor_val) < 0) { /* cannot get right factors for clk,just break */ WARN(1, "clk %s set rate failed! Because cannot get right factors for clk\n", hw->clk->name); return 0; } if(factor->flags & CLK_RATE_FLAT_FACTORS) return sunxi_clk_factors_set_flat_facotrs(factor, &factor_val); if(factor->lock) spin_lock_irqsave(factor->lock, flags); sunxi_clk_disable_plllock(factor); reg = factor_readl(factor, factor->reg); if(config->sdmwidth) { factor_writel(factor, config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } if(config->nwidth) reg = SET_BITS(config->nshift, config->nwidth, reg, factor_val.factorn); if(config->kwidth) reg = SET_BITS(config->kshift, config->kwidth, reg, factor_val.factork); if(config->mwidth) reg = SET_BITS(config->mshift, config->mwidth, reg, factor_val.factorm); if(config->pwidth) reg = SET_BITS(config->pshift, config->pwidth, reg, factor_val.factorp); if(config->d1width) reg = SET_BITS(config->d1shift, config->d1width, reg, factor_val.factord1); if(config->d2width) reg = SET_BITS(config->d2shift, config->d2width, reg, factor_val.factord2); if(config->frac) { reg = SET_BITS(config->modeshift, 1, reg, factor_val.frac_mode); reg = SET_BITS(config->outshift, 1, reg, factor_val.frac_freq); } if(config->updshift) //update for pll_ddr register reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); #ifndef CONFIG_SUNXI_CLK_DUMMY_DEBUG if(GET_BITS(config->enshift, 1, reg)) { if (sunxi_clk_is_lock(factor)) { if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; } } #endif if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; unsigned long orig_jiffies; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; if(!factor->get_factors) return 0; factor->get_factors(rate, parent_rate, &factor_val); reg = factor_readl(factor,factor->reg); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } if(config->nwidth) reg = SET_BITS(config->nshift, config->nwidth, reg, factor_val.factorn); if(config->kwidth) reg = SET_BITS(config->kshift, config->kwidth, reg, factor_val.factork); if(config->mwidth) reg = SET_BITS(config->mshift, config->mwidth, reg, factor_val.factorm); if(config->pwidth) reg = SET_BITS(config->pshift, config->pwidth, reg, factor_val.factorp); if(config->d1width) reg = SET_BITS(config->d1shift, config->d1width, reg, factor_val.factord1); if(config->d2width) reg = SET_BITS(config->d2shift, config->d2width, reg, factor_val.factord2); if(config->frac) { reg = SET_BITS(config->modeshift, 1, reg, factor_val.frac_mode); reg = SET_BITS(config->outshift, 1, reg, factor_val.frac_freq); } factor_writel(factor,reg, factor->reg); #ifndef CONFIG_SUNXI_CLK_DUMMY_DEBUG orig_jiffies = jiffies; if(GET_BITS(config->enshift, 1, reg)) { while(1) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) break; if(time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n",hw->clk->name); #else WARN(1, "clk %s wait lock timeout\n",hw->clk->name); #endif break; } } } #endif return 0; }