1*89a3dfb7SMaxime Ripard /* 2*89a3dfb7SMaxime Ripard * Copyright (C) 2016 Maxime Ripard 3*89a3dfb7SMaxime Ripard * Maxime Ripard <maxime.ripard@free-electrons.com> 4*89a3dfb7SMaxime Ripard * 5*89a3dfb7SMaxime Ripard * This program is free software; you can redistribute it and/or 6*89a3dfb7SMaxime Ripard * modify it under the terms of the GNU General Public License as 7*89a3dfb7SMaxime Ripard * published by the Free Software Foundation; either version 2 of 8*89a3dfb7SMaxime Ripard * the License, or (at your option) any later version. 9*89a3dfb7SMaxime Ripard */ 10*89a3dfb7SMaxime Ripard 11*89a3dfb7SMaxime Ripard #include <linux/clk-provider.h> 12*89a3dfb7SMaxime Ripard #include <linux/spinlock.h> 13*89a3dfb7SMaxime Ripard 14*89a3dfb7SMaxime Ripard #include "ccu_frac.h" 15*89a3dfb7SMaxime Ripard 16*89a3dfb7SMaxime Ripard bool ccu_frac_helper_is_enabled(struct ccu_common *common, 17*89a3dfb7SMaxime Ripard struct _ccu_frac *cf) 18*89a3dfb7SMaxime Ripard { 19*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 20*89a3dfb7SMaxime Ripard return false; 21*89a3dfb7SMaxime Ripard 22*89a3dfb7SMaxime Ripard return !(readl(common->base + common->reg) & cf->enable); 23*89a3dfb7SMaxime Ripard } 24*89a3dfb7SMaxime Ripard 25*89a3dfb7SMaxime Ripard void ccu_frac_helper_enable(struct ccu_common *common, 26*89a3dfb7SMaxime Ripard struct _ccu_frac *cf) 27*89a3dfb7SMaxime Ripard { 28*89a3dfb7SMaxime Ripard unsigned long flags; 29*89a3dfb7SMaxime Ripard u32 reg; 30*89a3dfb7SMaxime Ripard 31*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 32*89a3dfb7SMaxime Ripard return; 33*89a3dfb7SMaxime Ripard 34*89a3dfb7SMaxime Ripard spin_lock_irqsave(common->lock, flags); 35*89a3dfb7SMaxime Ripard reg = readl(common->base + common->reg); 36*89a3dfb7SMaxime Ripard writel(reg & ~cf->enable, common->base + common->reg); 37*89a3dfb7SMaxime Ripard spin_unlock_irqrestore(common->lock, flags); 38*89a3dfb7SMaxime Ripard } 39*89a3dfb7SMaxime Ripard 40*89a3dfb7SMaxime Ripard void ccu_frac_helper_disable(struct ccu_common *common, 41*89a3dfb7SMaxime Ripard struct _ccu_frac *cf) 42*89a3dfb7SMaxime Ripard { 43*89a3dfb7SMaxime Ripard unsigned long flags; 44*89a3dfb7SMaxime Ripard u32 reg; 45*89a3dfb7SMaxime Ripard 46*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 47*89a3dfb7SMaxime Ripard return; 48*89a3dfb7SMaxime Ripard 49*89a3dfb7SMaxime Ripard spin_lock_irqsave(common->lock, flags); 50*89a3dfb7SMaxime Ripard reg = readl(common->base + common->reg); 51*89a3dfb7SMaxime Ripard writel(reg | cf->enable, common->base + common->reg); 52*89a3dfb7SMaxime Ripard spin_unlock_irqrestore(common->lock, flags); 53*89a3dfb7SMaxime Ripard } 54*89a3dfb7SMaxime Ripard 55*89a3dfb7SMaxime Ripard bool ccu_frac_helper_has_rate(struct ccu_common *common, 56*89a3dfb7SMaxime Ripard struct _ccu_frac *cf, 57*89a3dfb7SMaxime Ripard unsigned long rate) 58*89a3dfb7SMaxime Ripard { 59*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 60*89a3dfb7SMaxime Ripard return false; 61*89a3dfb7SMaxime Ripard 62*89a3dfb7SMaxime Ripard return (cf->rates[0] == rate) || (cf->rates[1] == rate); 63*89a3dfb7SMaxime Ripard } 64*89a3dfb7SMaxime Ripard 65*89a3dfb7SMaxime Ripard unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, 66*89a3dfb7SMaxime Ripard struct _ccu_frac *cf) 67*89a3dfb7SMaxime Ripard { 68*89a3dfb7SMaxime Ripard u32 reg; 69*89a3dfb7SMaxime Ripard 70*89a3dfb7SMaxime Ripard printk("%s: Read fractional\n", clk_hw_get_name(&common->hw)); 71*89a3dfb7SMaxime Ripard 72*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 73*89a3dfb7SMaxime Ripard return 0; 74*89a3dfb7SMaxime Ripard 75*89a3dfb7SMaxime Ripard printk("%s: clock is fractional (rates %lu and %lu)\n", 76*89a3dfb7SMaxime Ripard clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]); 77*89a3dfb7SMaxime Ripard 78*89a3dfb7SMaxime Ripard reg = readl(common->base + common->reg); 79*89a3dfb7SMaxime Ripard 80*89a3dfb7SMaxime Ripard printk("%s: clock reg is 0x%x (select is 0x%x)\n", 81*89a3dfb7SMaxime Ripard clk_hw_get_name(&common->hw), reg, cf->select); 82*89a3dfb7SMaxime Ripard 83*89a3dfb7SMaxime Ripard return (reg & cf->select) ? cf->rates[1] : cf->rates[0]; 84*89a3dfb7SMaxime Ripard } 85*89a3dfb7SMaxime Ripard 86*89a3dfb7SMaxime Ripard int ccu_frac_helper_set_rate(struct ccu_common *common, 87*89a3dfb7SMaxime Ripard struct _ccu_frac *cf, 88*89a3dfb7SMaxime Ripard unsigned long rate) 89*89a3dfb7SMaxime Ripard { 90*89a3dfb7SMaxime Ripard unsigned long flags; 91*89a3dfb7SMaxime Ripard u32 reg, sel; 92*89a3dfb7SMaxime Ripard 93*89a3dfb7SMaxime Ripard if (!(common->features & CCU_FEATURE_FRACTIONAL)) 94*89a3dfb7SMaxime Ripard return -EINVAL; 95*89a3dfb7SMaxime Ripard 96*89a3dfb7SMaxime Ripard if (cf->rates[0] == rate) 97*89a3dfb7SMaxime Ripard sel = 0; 98*89a3dfb7SMaxime Ripard else if (cf->rates[1] == rate) 99*89a3dfb7SMaxime Ripard sel = cf->select; 100*89a3dfb7SMaxime Ripard else 101*89a3dfb7SMaxime Ripard return -EINVAL; 102*89a3dfb7SMaxime Ripard 103*89a3dfb7SMaxime Ripard spin_lock_irqsave(common->lock, flags); 104*89a3dfb7SMaxime Ripard reg = readl(common->base + common->reg); 105*89a3dfb7SMaxime Ripard reg &= ~cf->select; 106*89a3dfb7SMaxime Ripard writel(reg | sel, common->base + common->reg); 107*89a3dfb7SMaxime Ripard spin_unlock_irqrestore(common->lock, flags); 108*89a3dfb7SMaxime Ripard 109*89a3dfb7SMaxime Ripard return 0; 110*89a3dfb7SMaxime Ripard } 111