0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/log2.h>
0013
0014 #include "clk-factors.h"
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 static void sun9i_a80_get_pll4_factors(struct factors_request *req)
0027 {
0028 int n;
0029 int m = 1;
0030 int p = 1;
0031
0032
0033 n = DIV_ROUND_UP(req->rate, 6000000);
0034
0035
0036 if (n > 255) {
0037 m = 0;
0038 n = (n + 1) / 2;
0039 }
0040
0041
0042 if (n > 255) {
0043 p = 0;
0044 n = (n + 1) / 2;
0045 }
0046
0047
0048 if (n > 255)
0049 n = 255;
0050 else if (n < 12)
0051 n = 12;
0052
0053 req->rate = ((24000000 * n) >> p) / (m + 1);
0054 req->n = n;
0055 req->m = m;
0056 req->p = p;
0057 }
0058
0059 static const struct clk_factors_config sun9i_a80_pll4_config = {
0060 .mshift = 18,
0061 .mwidth = 1,
0062 .nshift = 8,
0063 .nwidth = 8,
0064 .pshift = 16,
0065 .pwidth = 1,
0066 };
0067
0068 static const struct factors_data sun9i_a80_pll4_data __initconst = {
0069 .enable = 31,
0070 .table = &sun9i_a80_pll4_config,
0071 .getter = sun9i_a80_get_pll4_factors,
0072 };
0073
0074 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
0075
0076 static void __init sun9i_a80_pll4_setup(struct device_node *node)
0077 {
0078 void __iomem *reg;
0079
0080 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0081 if (IS_ERR(reg)) {
0082 pr_err("Could not get registers for a80-pll4-clk: %pOFn\n",
0083 node);
0084 return;
0085 }
0086
0087 sunxi_factors_register(node, &sun9i_a80_pll4_data,
0088 &sun9i_a80_pll4_lock, reg);
0089 }
0090 CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
0091
0092
0093
0094
0095
0096
0097
0098
0099 static void sun9i_a80_get_gt_factors(struct factors_request *req)
0100 {
0101 u32 div;
0102
0103 if (req->parent_rate < req->rate)
0104 req->rate = req->parent_rate;
0105
0106 div = DIV_ROUND_UP(req->parent_rate, req->rate);
0107
0108
0109 if (div > 4)
0110 div = 4;
0111
0112 req->rate = req->parent_rate / div;
0113 req->m = div;
0114 }
0115
0116 static const struct clk_factors_config sun9i_a80_gt_config = {
0117 .mshift = 0,
0118 .mwidth = 2,
0119 };
0120
0121 static const struct factors_data sun9i_a80_gt_data __initconst = {
0122 .mux = 24,
0123 .muxmask = BIT(1) | BIT(0),
0124 .table = &sun9i_a80_gt_config,
0125 .getter = sun9i_a80_get_gt_factors,
0126 };
0127
0128 static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
0129
0130 static void __init sun9i_a80_gt_setup(struct device_node *node)
0131 {
0132 void __iomem *reg;
0133
0134 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0135 if (IS_ERR(reg)) {
0136 pr_err("Could not get registers for a80-gt-clk: %pOFn\n",
0137 node);
0138 return;
0139 }
0140
0141
0142 sunxi_factors_register_critical(node, &sun9i_a80_gt_data,
0143 &sun9i_a80_gt_lock, reg);
0144 }
0145 CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
0146
0147
0148
0149
0150
0151
0152
0153
0154 static void sun9i_a80_get_ahb_factors(struct factors_request *req)
0155 {
0156 u32 _p;
0157
0158 if (req->parent_rate < req->rate)
0159 req->rate = req->parent_rate;
0160
0161 _p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
0162
0163
0164 if (_p > 3)
0165 _p = 3;
0166
0167 req->rate = req->parent_rate >> _p;
0168 req->p = _p;
0169 }
0170
0171 static const struct clk_factors_config sun9i_a80_ahb_config = {
0172 .pshift = 0,
0173 .pwidth = 2,
0174 };
0175
0176 static const struct factors_data sun9i_a80_ahb_data __initconst = {
0177 .mux = 24,
0178 .muxmask = BIT(1) | BIT(0),
0179 .table = &sun9i_a80_ahb_config,
0180 .getter = sun9i_a80_get_ahb_factors,
0181 };
0182
0183 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
0184
0185 static void __init sun9i_a80_ahb_setup(struct device_node *node)
0186 {
0187 void __iomem *reg;
0188
0189 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0190 if (IS_ERR(reg)) {
0191 pr_err("Could not get registers for a80-ahb-clk: %pOFn\n",
0192 node);
0193 return;
0194 }
0195
0196 sunxi_factors_register(node, &sun9i_a80_ahb_data,
0197 &sun9i_a80_ahb_lock, reg);
0198 }
0199 CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
0200
0201
0202 static const struct factors_data sun9i_a80_apb0_data __initconst = {
0203 .mux = 24,
0204 .muxmask = BIT(0),
0205 .table = &sun9i_a80_ahb_config,
0206 .getter = sun9i_a80_get_ahb_factors,
0207 };
0208
0209 static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
0210
0211 static void __init sun9i_a80_apb0_setup(struct device_node *node)
0212 {
0213 void __iomem *reg;
0214
0215 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0216 if (IS_ERR(reg)) {
0217 pr_err("Could not get registers for a80-apb0-clk: %pOFn\n",
0218 node);
0219 return;
0220 }
0221
0222 sunxi_factors_register(node, &sun9i_a80_apb0_data,
0223 &sun9i_a80_apb0_lock, reg);
0224 }
0225 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
0226
0227
0228
0229
0230
0231
0232
0233
0234 static void sun9i_a80_get_apb1_factors(struct factors_request *req)
0235 {
0236 u32 div;
0237
0238 if (req->parent_rate < req->rate)
0239 req->rate = req->parent_rate;
0240
0241 div = DIV_ROUND_UP(req->parent_rate, req->rate);
0242
0243
0244 if (div > 256)
0245 div = 256;
0246
0247 req->p = order_base_2(div);
0248 req->m = (req->parent_rate >> req->p) - 1;
0249 req->rate = (req->parent_rate >> req->p) / (req->m + 1);
0250 }
0251
0252 static const struct clk_factors_config sun9i_a80_apb1_config = {
0253 .mshift = 0,
0254 .mwidth = 5,
0255 .pshift = 16,
0256 .pwidth = 2,
0257 };
0258
0259 static const struct factors_data sun9i_a80_apb1_data __initconst = {
0260 .mux = 24,
0261 .muxmask = BIT(0),
0262 .table = &sun9i_a80_apb1_config,
0263 .getter = sun9i_a80_get_apb1_factors,
0264 };
0265
0266 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
0267
0268 static void __init sun9i_a80_apb1_setup(struct device_node *node)
0269 {
0270 void __iomem *reg;
0271
0272 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0273 if (IS_ERR(reg)) {
0274 pr_err("Could not get registers for a80-apb1-clk: %pOFn\n",
0275 node);
0276 return;
0277 }
0278
0279 sunxi_factors_register(node, &sun9i_a80_apb1_data,
0280 &sun9i_a80_apb1_lock, reg);
0281 }
0282 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);