static int sunxi_clk_periph_set_parent(struct clk_hw *hw, u8 index) { unsigned long reg, flags = 0; struct sunxi_clk_periph *periph = to_clk_periph(hw); if(periph->flags & CLK_READONLY) return 0; if(!periph->mux.reg) return 0; if(periph->lock) { spin_lock_irqsave(periph->lock, flags); reg = periph_readl(periph,periph->mux.reg); reg = SET_BITS(periph->mux.shift, periph->mux.width, reg, index); periph_writel(periph,reg, periph->mux.reg); spin_unlock_irqrestore(periph->lock, flags); } else { reg = periph_readl(periph,periph->mux.reg); reg = SET_BITS(periph->mux.shift, periph->mux.width, reg, index); periph_writel(periph,reg, periph->mux.reg); } return 0; }
static int __sunxi_clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct sunxi_clk_periph *periph = to_clk_periph(hw); struct sunxi_clk_periph_div *divider = &periph->divider; int i,j,m_max; int m=0,n=0; unsigned long cur_rate=0,new_rate=0; unsigned long cur_delta,new_delta; u32 reg; if(parent_rate == 4000000) m_max =1; else m_max = 8; for(i=0;i<m_max;i++) for(j=0;j<8;j++) { new_rate = parent_rate/(ac100_m_factor[i]*ac100_n_factor[j]); new_delta = (new_rate >rate)?(new_rate-rate):(rate-new_rate); cur_delta = (cur_rate >rate)?(cur_rate-rate):(rate-cur_rate); if(new_delta < cur_delta) { cur_rate = new_rate; m =i; n = j; } } reg = periph_readl(periph,divider->reg); if(divider->mwidth) reg = SET_BITS(divider->mshift, divider->mwidth, reg, m); if(divider->nwidth) reg = SET_BITS(divider->nshift, divider->nwidth, reg, n); periph_writel(periph,reg, divider->reg); return 0; }
static int __sunxi_clk_periph_enable_shared(struct sunxi_clk_periph *periph) { unsigned long reg; struct sunxi_clk_periph_gate *gate = &periph->gate; if(!periph->com_gate) return -1; if(!periph->com_gate->val) { /* de-assert module */ if(gate->reset && !(periph->flags & CLK_IGNORE_AUTORESET) && IS_SHARE_RST_GATE(periph)) { reg = periph_readl(periph,gate->reset); reg = SET_BITS(gate->rst_shift, 1, reg, 1); periph_writel(periph,reg, gate->reset); } /* enable bus gating */ if(gate->bus && IS_SHARE_BUS_GATE(periph)) { reg = periph_readl(periph,gate->bus); reg = SET_BITS(gate->bus_shift, 1, reg, 1); periph_writel(periph,reg, gate->bus); } /* enable module gating */ if(gate->enable&& IS_SHARE_MOD_GATE(periph)) { reg = periph_readl(periph,gate->enable); reg = SET_BITS(gate->enb_shift, 1, reg, 1); periph_writel(periph,reg, gate->enable); } /* enable dram gating */ if(gate->dram&& IS_SHARE_MBUS_GATE(periph)) { reg = periph_readl(periph,gate->dram); reg = SET_BITS(gate->ddr_shift, 1, reg, 1); periph_writel(periph,reg, gate->dram); } } periph->com_gate->val |= 1 << periph->com_gate_off; return 0; }
static int __sunxi_clk_periph_enable(struct clk_hw *hw) { unsigned long reg; struct sunxi_clk_periph *periph = to_clk_periph(hw); struct sunxi_clk_periph_gate *gate = &periph->gate; /* de-assert module */ if(gate->reset && !(periph->flags & CLK_IGNORE_AUTORESET) && !IS_SHARE_RST_GATE(periph)) { reg = periph_readl(periph,gate->reset); reg = SET_BITS(gate->rst_shift, 1, reg, 1); periph_writel(periph,reg, gate->reset); } /* enable bus gating */ if(gate->bus && !IS_SHARE_BUS_GATE(periph)) { reg = periph_readl(periph,gate->bus); reg = SET_BITS(gate->bus_shift, 1, reg, 1); periph_writel(periph,reg, gate->bus); } /* enable module gating */ if(gate->enable&& !IS_SHARE_MOD_GATE(periph)) { reg = periph_readl(periph,gate->enable); if(periph->flags & CLK_REVERT_ENABLE) reg = SET_BITS(gate->enb_shift, 1, reg, 0); else reg = SET_BITS(gate->enb_shift, 1, reg, 1); periph_writel(periph,reg, gate->enable); } /* enable dram gating */ if(gate->dram&& !IS_SHARE_MBUS_GATE(periph)) { reg = periph_readl(periph,gate->dram); reg = SET_BITS(gate->ddr_shift, 1, reg, 1); periph_writel(periph,reg, gate->dram); } return 0; }