Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: mmp: add mmp specific clocks

add mmp specific clocks including apbc cloks, apmu clocks,
and pll2, fraction clocks

Signed-off-by: Chao Xie <xiechao.mail@gmail.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Chao Xie and committed by
Mike Turquette
6b63f023 f9a6aa43

+445
+3
drivers/clk/Makefile
··· 11 11 obj-$(CONFIG_ARCH_U300) += clk-u300.o 12 12 obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ 13 13 obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o 14 + ifeq ($(CONFIG_COMMON_CLK), y) 15 + obj-$(CONFIG_ARCH_MMP) += mmp/ 16 + endif 14 17 15 18 # Chip specific 16 19 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
+5
drivers/clk/mmp/Makefile
··· 1 + # 2 + # Makefile for mmp specific clk 3 + # 4 + 5 + obj-y += clk-apbc.o clk-apmu.o clk-frac.o
+152
drivers/clk/mmp/clk-apbc.c
··· 1 + /* 2 + * mmp APB clock operation source file 3 + * 4 + * Copyright (C) 2012 Marvell 5 + * Chao Xie <xiechao.mail@gmail.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public 8 + * License version 2. This program is licensed "as is" without any 9 + * warranty of any kind, whether express or implied. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/clk.h> 14 + #include <linux/io.h> 15 + #include <linux/err.h> 16 + #include <linux/delay.h> 17 + #include <linux/slab.h> 18 + 19 + #include "clk.h" 20 + 21 + /* Common APB clock register bit definitions */ 22 + #define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */ 23 + #define APBC_FNCLK (1 << 1) /* Functional Clock Enable */ 24 + #define APBC_RST (1 << 2) /* Reset Generation */ 25 + #define APBC_POWER (1 << 7) /* Reset Generation */ 26 + 27 + #define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw) 28 + struct clk_apbc { 29 + struct clk_hw hw; 30 + void __iomem *base; 31 + unsigned int delay; 32 + unsigned int flags; 33 + spinlock_t *lock; 34 + }; 35 + 36 + static int clk_apbc_prepare(struct clk_hw *hw) 37 + { 38 + struct clk_apbc *apbc = to_clk_apbc(hw); 39 + unsigned int data; 40 + unsigned long flags = 0; 41 + 42 + /* 43 + * It may share same register as MUX clock, 44 + * and it will impact FNCLK enable. Spinlock is needed 45 + */ 46 + if (apbc->lock) 47 + spin_lock_irqsave(apbc->lock, flags); 48 + 49 + data = readl_relaxed(apbc->base); 50 + if (apbc->flags & APBC_POWER_CTRL) 51 + data |= APBC_POWER; 52 + data |= APBC_FNCLK; 53 + writel_relaxed(data, apbc->base); 54 + 55 + if (apbc->lock) 56 + spin_unlock_irqrestore(apbc->lock, flags); 57 + 58 + udelay(apbc->delay); 59 + 60 + if (apbc->lock) 61 + spin_lock_irqsave(apbc->lock, flags); 62 + 63 + data = readl_relaxed(apbc->base); 64 + data |= APBC_APBCLK; 65 + writel_relaxed(data, apbc->base); 66 + 67 + if (apbc->lock) 68 + spin_unlock_irqrestore(apbc->lock, flags); 69 + 70 + udelay(apbc->delay); 71 + 72 + if (!(apbc->flags & APBC_NO_BUS_CTRL)) { 73 + if (apbc->lock) 74 + spin_lock_irqsave(apbc->lock, flags); 75 + 76 + data = readl_relaxed(apbc->base); 77 + data &= ~APBC_RST; 78 + writel_relaxed(data, apbc->base); 79 + 80 + if (apbc->lock) 81 + spin_unlock_irqrestore(apbc->lock, flags); 82 + } 83 + 84 + return 0; 85 + } 86 + 87 + static void clk_apbc_unprepare(struct clk_hw *hw) 88 + { 89 + struct clk_apbc *apbc = to_clk_apbc(hw); 90 + unsigned long data; 91 + unsigned long flags = 0; 92 + 93 + if (apbc->lock) 94 + spin_lock_irqsave(apbc->lock, flags); 95 + 96 + data = readl_relaxed(apbc->base); 97 + if (apbc->flags & APBC_POWER_CTRL) 98 + data &= ~APBC_POWER; 99 + data &= ~APBC_FNCLK; 100 + writel_relaxed(data, apbc->base); 101 + 102 + if (apbc->lock) 103 + spin_unlock_irqrestore(apbc->lock, flags); 104 + 105 + udelay(10); 106 + 107 + if (apbc->lock) 108 + spin_lock_irqsave(apbc->lock, flags); 109 + 110 + data = readl_relaxed(apbc->base); 111 + data &= ~APBC_APBCLK; 112 + writel_relaxed(data, apbc->base); 113 + 114 + if (apbc->lock) 115 + spin_unlock_irqrestore(apbc->lock, flags); 116 + } 117 + 118 + struct clk_ops clk_apbc_ops = { 119 + .prepare = clk_apbc_prepare, 120 + .unprepare = clk_apbc_unprepare, 121 + }; 122 + 123 + struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name, 124 + void __iomem *base, unsigned int delay, 125 + unsigned int apbc_flags, spinlock_t *lock) 126 + { 127 + struct clk_apbc *apbc; 128 + struct clk *clk; 129 + struct clk_init_data init; 130 + 131 + apbc = kzalloc(sizeof(*apbc), GFP_KERNEL); 132 + if (!apbc) 133 + return NULL; 134 + 135 + init.name = name; 136 + init.ops = &clk_apbc_ops; 137 + init.flags = CLK_SET_RATE_PARENT; 138 + init.parent_names = (parent_name ? &parent_name : NULL); 139 + init.num_parents = (parent_name ? 1 : 0); 140 + 141 + apbc->base = base; 142 + apbc->delay = delay; 143 + apbc->flags = apbc_flags; 144 + apbc->lock = lock; 145 + apbc->hw.init = &init; 146 + 147 + clk = clk_register(NULL, &apbc->hw); 148 + if (IS_ERR(clk)) 149 + kfree(apbc); 150 + 151 + return clk; 152 + }
+97
drivers/clk/mmp/clk-apmu.c
··· 1 + /* 2 + * mmp AXI peripharal clock operation source file 3 + * 4 + * Copyright (C) 2012 Marvell 5 + * Chao Xie <xiechao.mail@gmail.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public 8 + * License version 2. This program is licensed "as is" without any 9 + * warranty of any kind, whether express or implied. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/clk.h> 14 + #include <linux/io.h> 15 + #include <linux/err.h> 16 + #include <linux/delay.h> 17 + #include <linux/slab.h> 18 + 19 + #include "clk.h" 20 + 21 + #define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk)) 22 + struct clk_apmu { 23 + struct clk_hw hw; 24 + void __iomem *base; 25 + u32 rst_mask; 26 + u32 enable_mask; 27 + spinlock_t *lock; 28 + }; 29 + 30 + static int clk_apmu_enable(struct clk_hw *hw) 31 + { 32 + struct clk_apmu *apmu = to_clk_apmu(hw); 33 + unsigned long data; 34 + unsigned long flags = 0; 35 + 36 + if (apmu->lock) 37 + spin_lock_irqsave(apmu->lock, flags); 38 + 39 + data = readl_relaxed(apmu->base) | apmu->enable_mask; 40 + writel_relaxed(data, apmu->base); 41 + 42 + if (apmu->lock) 43 + spin_unlock_irqrestore(apmu->lock, flags); 44 + 45 + return 0; 46 + } 47 + 48 + static void clk_apmu_disable(struct clk_hw *hw) 49 + { 50 + struct clk_apmu *apmu = to_clk_apmu(hw); 51 + unsigned long data; 52 + unsigned long flags = 0; 53 + 54 + if (apmu->lock) 55 + spin_lock_irqsave(apmu->lock, flags); 56 + 57 + data = readl_relaxed(apmu->base) & ~apmu->enable_mask; 58 + writel_relaxed(data, apmu->base); 59 + 60 + if (apmu->lock) 61 + spin_unlock_irqrestore(apmu->lock, flags); 62 + } 63 + 64 + struct clk_ops clk_apmu_ops = { 65 + .enable = clk_apmu_enable, 66 + .disable = clk_apmu_disable, 67 + }; 68 + 69 + struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, 70 + void __iomem *base, u32 enable_mask, spinlock_t *lock) 71 + { 72 + struct clk_apmu *apmu; 73 + struct clk *clk; 74 + struct clk_init_data init; 75 + 76 + apmu = kzalloc(sizeof(*apmu), GFP_KERNEL); 77 + if (!apmu) 78 + return NULL; 79 + 80 + init.name = name; 81 + init.ops = &clk_apmu_ops; 82 + init.flags = CLK_SET_RATE_PARENT; 83 + init.parent_names = (parent_name ? &parent_name : NULL); 84 + init.num_parents = (parent_name ? 1 : 0); 85 + 86 + apmu->base = base; 87 + apmu->enable_mask = enable_mask; 88 + apmu->lock = lock; 89 + apmu->hw.init = &init; 90 + 91 + clk = clk_register(NULL, &apmu->hw); 92 + 93 + if (IS_ERR(clk)) 94 + kfree(apmu); 95 + 96 + return clk; 97 + }
+153
drivers/clk/mmp/clk-frac.c
··· 1 + /* 2 + * mmp factor clock operation source file 3 + * 4 + * Copyright (C) 2012 Marvell 5 + * Chao Xie <xiechao.mail@gmail.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public 8 + * License version 2. This program is licensed "as is" without any 9 + * warranty of any kind, whether express or implied. 10 + */ 11 + 12 + #include <linux/clk-provider.h> 13 + #include <linux/slab.h> 14 + #include <linux/io.h> 15 + #include <linux/err.h> 16 + 17 + #include "clk.h" 18 + /* 19 + * It is M/N clock 20 + * 21 + * Fout from synthesizer can be given from two equations: 22 + * numerator/denominator = Fin / (Fout * factor) 23 + */ 24 + 25 + #define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) 26 + struct clk_factor { 27 + struct clk_hw hw; 28 + void __iomem *base; 29 + struct clk_factor_masks *masks; 30 + struct clk_factor_tbl *ftbl; 31 + unsigned int ftbl_cnt; 32 + }; 33 + 34 + static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, 35 + unsigned long *prate) 36 + { 37 + struct clk_factor *factor = to_clk_factor(hw); 38 + unsigned long rate = 0, prev_rate; 39 + int i; 40 + 41 + for (i = 0; i < factor->ftbl_cnt; i++) { 42 + prev_rate = rate; 43 + rate = (((*prate / 10000) * factor->ftbl[i].num) / 44 + (factor->ftbl[i].den * factor->masks->factor)) * 10000; 45 + if (rate > drate) 46 + break; 47 + } 48 + if (i == 0) 49 + return rate; 50 + else 51 + return prev_rate; 52 + } 53 + 54 + static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, 55 + unsigned long parent_rate) 56 + { 57 + struct clk_factor *factor = to_clk_factor(hw); 58 + struct clk_factor_masks *masks = factor->masks; 59 + unsigned int val, num, den; 60 + 61 + val = readl_relaxed(factor->base); 62 + 63 + /* calculate numerator */ 64 + num = (val >> masks->num_shift) & masks->num_mask; 65 + 66 + /* calculate denominator */ 67 + den = (val >> masks->den_shift) & masks->num_mask; 68 + 69 + if (!den) 70 + return 0; 71 + 72 + return (((parent_rate / 10000) * den) / 73 + (num * factor->masks->factor)) * 10000; 74 + } 75 + 76 + /* Configures new clock rate*/ 77 + static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, 78 + unsigned long prate) 79 + { 80 + struct clk_factor *factor = to_clk_factor(hw); 81 + struct clk_factor_masks *masks = factor->masks; 82 + int i; 83 + unsigned long val; 84 + unsigned long prev_rate, rate = 0; 85 + 86 + for (i = 0; i < factor->ftbl_cnt; i++) { 87 + prev_rate = rate; 88 + rate = (((prate / 10000) * factor->ftbl[i].num) / 89 + (factor->ftbl[i].den * factor->masks->factor)) * 10000; 90 + if (rate > drate) 91 + break; 92 + } 93 + if (i > 0) 94 + i--; 95 + 96 + val = readl_relaxed(factor->base); 97 + 98 + val &= ~(masks->num_mask << masks->num_shift); 99 + val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift; 100 + 101 + val &= ~(masks->den_mask << masks->den_shift); 102 + val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift; 103 + 104 + writel_relaxed(val, factor->base); 105 + 106 + return 0; 107 + } 108 + 109 + static struct clk_ops clk_factor_ops = { 110 + .recalc_rate = clk_factor_recalc_rate, 111 + .round_rate = clk_factor_round_rate, 112 + .set_rate = clk_factor_set_rate, 113 + }; 114 + 115 + struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, 116 + unsigned long flags, void __iomem *base, 117 + struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, 118 + unsigned int ftbl_cnt) 119 + { 120 + struct clk_factor *factor; 121 + struct clk_init_data init; 122 + struct clk *clk; 123 + 124 + if (!masks) { 125 + pr_err("%s: must pass a clk_factor_mask\n", __func__); 126 + return ERR_PTR(-EINVAL); 127 + } 128 + 129 + factor = kzalloc(sizeof(*factor), GFP_KERNEL); 130 + if (!factor) { 131 + pr_err("%s: could not allocate factor clk\n", __func__); 132 + return ERR_PTR(-ENOMEM); 133 + } 134 + 135 + /* struct clk_aux assignments */ 136 + factor->base = base; 137 + factor->masks = masks; 138 + factor->ftbl = ftbl; 139 + factor->ftbl_cnt = ftbl_cnt; 140 + factor->hw.init = &init; 141 + 142 + init.name = name; 143 + init.ops = &clk_factor_ops; 144 + init.flags = flags; 145 + init.parent_names = &parent_name; 146 + init.num_parents = 1; 147 + 148 + clk = clk_register(NULL, &factor->hw); 149 + if (IS_ERR_OR_NULL(clk)) 150 + kfree(factor); 151 + 152 + return clk; 153 + }
+35
drivers/clk/mmp/clk.h
··· 1 + #ifndef __MACH_MMP_CLK_H 2 + #define __MACH_MMP_CLK_H 3 + 4 + #include <linux/clk-provider.h> 5 + #include <linux/clkdev.h> 6 + 7 + #define APBC_NO_BUS_CTRL BIT(0) 8 + #define APBC_POWER_CTRL BIT(1) 9 + 10 + struct clk_factor_masks { 11 + unsigned int factor; 12 + unsigned int num_mask; 13 + unsigned int den_mask; 14 + unsigned int num_shift; 15 + unsigned int den_shift; 16 + }; 17 + 18 + struct clk_factor_tbl { 19 + unsigned int num; 20 + unsigned int den; 21 + }; 22 + 23 + extern struct clk *mmp_clk_register_pll2(const char *name, 24 + const char *parent_name, unsigned long flags); 25 + extern struct clk *mmp_clk_register_apbc(const char *name, 26 + const char *parent_name, void __iomem *base, 27 + unsigned int delay, unsigned int apbc_flags, spinlock_t *lock); 28 + extern struct clk *mmp_clk_register_apmu(const char *name, 29 + const char *parent_name, void __iomem *base, u32 enable_mask, 30 + spinlock_t *lock); 31 + extern struct clk *mmp_clk_register_factor(const char *name, 32 + const char *parent_name, unsigned long flags, 33 + void __iomem *base, struct clk_factor_masks *masks, 34 + struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt); 35 + #endif