diff options
Diffstat (limited to 'drivers/clk/socfpga')
-rw-r--r-- | drivers/clk/socfpga/clk-gate.c | 1 | ||||
-rw-r--r-- | drivers/clk/socfpga/clk-periph.c | 22 | ||||
-rw-r--r-- | drivers/clk/socfpga/clk-pll.c | 7 | ||||
-rw-r--r-- | drivers/clk/socfpga/clk.c | 23 | ||||
-rw-r--r-- | drivers/clk/socfpga/clk.h | 4 |
5 files changed, 33 insertions, 24 deletions
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 501d513bf890..dd3a78c64795 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -32,7 +32,6 @@ #define SOCFPGA_MMC_CLK "sdmmc_clk" #define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8 -#define div_mask(width) ((1 << (width)) - 1) #define streq(a, b) (strcmp((a), (b)) == 0) #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw) diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c index 81623a3736f9..46531c34ec9b 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c @@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, unsigned long parent_rate) { struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk); - u32 div; + u32 div, val; - if (socfpgaclk->fixed_div) + if (socfpgaclk->fixed_div) { div = socfpgaclk->fixed_div; - else + } else { + if (socfpgaclk->div_reg) { + val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; + val &= div_mask(socfpgaclk->width); + parent_rate /= (val + 1); + } div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1); + } return parent_rate / div; } @@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node, struct clk_init_data init; int rc; u32 fixed_div; + u32 div_reg[3]; of_property_read_u32(node, "reg", ®); @@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node, periph_clk->hw.reg = clk_mgr_base_addr + reg; + rc = of_property_read_u32_array(node, "div-reg", div_reg, 3); + if (!rc) { + periph_clk->div_reg = clk_mgr_base_addr + div_reg[0]; + periph_clk->shift = div_reg[1]; + periph_clk->width = div_reg[2]; + } else { + periph_clk->div_reg = 0; + } + rc = of_property_read_u32(node, "fixed-divider", &fixed_div); if (rc) periph_clk->fixed_div = 0; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index 88dafb5e9627..de6da957a09d 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -20,6 +20,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/of_address.h> #include "clk.h" @@ -43,6 +44,8 @@ #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) +void __iomem *clk_mgr_base_addr; + static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, unsigned long parent_rate) { @@ -87,6 +90,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; + struct device_node *clkmgr_np; int rc; int i = 0; @@ -96,6 +100,9 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, if (WARN_ON(!pll_clk)) return NULL; + clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); + clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; of_property_read_string(node, "clock-output-names", &clk_name); diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c index 35a960a993f9..43db947e5f0e 100644 --- a/drivers/clk/socfpga/clk.c +++ b/drivers/clk/socfpga/clk.c @@ -17,28 +17,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/clk-provider.h> -#include <linux/io.h> #include <linux/of.h> -#include <linux/of_address.h> #include "clk.h" -void __iomem *clk_mgr_base_addr; - -static const struct of_device_id socfpga_child_clocks[] __initconst = { - { .compatible = "altr,socfpga-pll-clock", socfpga_pll_init, }, - { .compatible = "altr,socfpga-perip-clk", socfpga_periph_init, }, - { .compatible = "altr,socfpga-gate-clk", socfpga_gate_init, }, - {}, -}; - -static void __init socfpga_clkmgr_init(struct device_node *node) -{ - clk_mgr_base_addr = of_iomap(node, 0); - of_clk_init(socfpga_child_clocks); -} -CLK_OF_DECLARE(socfpga_mgr, "altr,clk-mgr", socfpga_clkmgr_init); +CLK_OF_DECLARE(socfpga_pll_clk, "altr,socfpga-pll-clock", socfpga_pll_init); +CLK_OF_DECLARE(socfpga_perip_clk, "altr,socfpga-perip-clk", socfpga_periph_init); +CLK_OF_DECLARE(socfpga_gate_clk, "altr,socfpga-gate-clk", socfpga_gate_init); diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h index d2e54019c94f..d291f60c46e1 100644 --- a/drivers/clk/socfpga/clk.h +++ b/drivers/clk/socfpga/clk.h @@ -27,6 +27,7 @@ #define CLKMGR_PERPLL_SRC 0xAC #define SOCFPGA_MAX_PARENTS 3 +#define div_mask(width) ((1 << (width)) - 1) extern void __iomem *clk_mgr_base_addr; @@ -52,6 +53,9 @@ struct socfpga_periph_clk { struct clk_gate hw; char *parent_name; u32 fixed_div; + void __iomem *div_reg; + u32 width; /* only valid if div_reg != 0 */ + u32 shift; /* only valid if div_reg != 0 */ }; #endif /* SOCFPGA_CLK_H */ |