Commit 06a98527 authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'sunxi-clocks-for-4.6' of...

Merge tag 'sunxi-clocks-for-4.6' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next

Pull Allwinner clk updates from Maxime Ripard:

Allwinner clocks additions for 4.6

A bunch of things, mostly:
  - Finally switched everything over to OF_CLK_DECLARE, which should remove
    orphans clocks entirely
  - Reworked the clk-factors to be able to add new parameters
  - Improved the error reporting
  - A bunch of new clocks for new SoCs.

* tag 'sunxi-clocks-for-4.6' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux: (25 commits)
  clk: sunxi: Add apb0 gates for H3
  clk: sunxi: Improve divs_clk error handling and reporting
  clk: sunxi: improve divider_clk error handling and reporting
  clk: sunxi: improve mux_clk error handling and reporting
  clk: sunxi: Fix sun8i-a23-apb0-clk divider flags
  clk: sunxi: Remove clk_register_clkdev calls
  clk: sunxi: Remove old probe and protection code
  clk: sunxi: convert current clocks registration to CLK_OF_DECLARE
  clk: sunxi: Make clocks setup functions take const pointer
  clk: sunxi: Make clocks setup functions return their clock
  clk: sunxi: improve error reporting for the mux clock
  clk: sunxi: don't mark sun6i_ar100_data __initconst
  clk: sunxi: add bus gates for A83T
  clk: sunxi: Add apb0 gates for A83T
  clk: sunxi: rewrite sun8i-a23-mbus-clk using the simpler composite clk
  clk: sunxi: rewrite sun6i-ar100 using factors clk
  clk: sunxi: rewrite sun6i-a31-ahb1-clk using factors clk with custom recalc
  clk: sunxi: factors: Drop round_rate from clk ops
  clk: sunxi: factors: Support custom formulas
  clk: sunxi: factors: Consolidate get_factors parameters into a struct
  ...
parents 0f75e1a3 6e17b418
...@@ -18,6 +18,7 @@ Required properties: ...@@ -18,6 +18,7 @@ Required properties:
"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
"allwinner,sun4i-a10-axi-clk" - for the AXI clock "allwinner,sun4i-a10-axi-clk" - for the AXI clock
"allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
"allwinner,sun4i-a10-gates-clk" - for generic gates on all compatible SoCs
"allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-a10-ahb-clk" - for the AHB clock "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
"allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13 "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13
...@@ -39,12 +40,14 @@ Required properties: ...@@ -39,12 +40,14 @@ Required properties:
"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31 "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
"allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23 "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
"allwinner,sun9i-a80-apb0-clk" - for the APB0 bus clock on A80 "allwinner,sun9i-a80-apb0-clk" - for the APB0 bus clock on A80
"allwinner,sun8i-a83t-apb0-gates-clk" - for the APB0 gates on A83T
"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
"allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
"allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23
"allwinner,sun8i-h3-apb0-gates-clk" - for the APB0 gates on H3
"allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80
"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
"allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80
...@@ -57,6 +60,7 @@ Required properties: ...@@ -57,6 +60,7 @@ Required properties:
"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
"allwinner,sun8i-a83t-bus-gates-clk" - for the bus gates on A83T
"allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3
"allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
"allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.h>
#define SUNXI_OSC24M_GATE 0 #define SUNXI_OSC24M_GATE 0
...@@ -61,7 +61,6 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) ...@@ -61,7 +61,6 @@ static void __init sun4i_osc_clk_setup(struct device_node *node)
goto err_free_gate; goto err_free_gate;
of_clk_add_provider(node, of_clk_src_simple_get, clk); of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
return; return;
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -107,7 +106,6 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) ...@@ -107,7 +106,6 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
goto iounmap_reg; goto iounmap_reg;
of_clk_add_provider(node, of_clk_src_simple_get, clk); of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
return; return;
......
...@@ -48,7 +48,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw, ...@@ -48,7 +48,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
u32 reg; u32 reg;
unsigned long rate; unsigned long rate;
struct clk_factors *factors = to_clk_factors(hw); struct clk_factors *factors = to_clk_factors(hw);
struct clk_factors_config *config = factors->config; const struct clk_factors_config *config = factors->config;
/* Fetch the register value */ /* Fetch the register value */
reg = readl(factors->reg); reg = readl(factors->reg);
...@@ -63,18 +63,28 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw, ...@@ -63,18 +63,28 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE) if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
p = FACTOR_GET(config->pshift, config->pwidth, reg); p = FACTOR_GET(config->pshift, config->pwidth, reg);
/* Calculate the rate */ if (factors->recalc) {
rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1); struct factors_request factors_req = {
.parent_rate = parent_rate,
.n = n,
.k = k,
.m = m,
.p = p,
};
return rate; /* get mux details from mux clk structure */
} if (factors->mux)
factors_req.parent_index =
(reg >> factors->mux->shift) &
factors->mux->mask;
static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, factors->recalc(&factors_req);
unsigned long *parent_rate)
{ return factors_req.rate;
struct clk_factors *factors = to_clk_factors(hw); }
factors->get_factors((u32 *)&rate, (u32)*parent_rate,
NULL, NULL, NULL, NULL); /* Calculate the rate */
rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1);
return rate; return rate;
} }
...@@ -82,6 +92,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -82,6 +92,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
static int clk_factors_determine_rate(struct clk_hw *hw, static int clk_factors_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req) struct clk_rate_request *req)
{ {
struct clk_factors *factors = to_clk_factors(hw);
struct clk_hw *parent, *best_parent = NULL; struct clk_hw *parent, *best_parent = NULL;
int i, num_parents; int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0; unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
...@@ -89,6 +100,10 @@ static int clk_factors_determine_rate(struct clk_hw *hw, ...@@ -89,6 +100,10 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
/* find the parent that can help provide the fastest rate <= rate */ /* find the parent that can help provide the fastest rate <= rate */
num_parents = clk_hw_get_num_parents(hw); num_parents = clk_hw_get_num_parents(hw);
for (i = 0; i < num_parents; i++) { for (i = 0; i < num_parents; i++) {
struct factors_request factors_req = {
.rate = req->rate,
.parent_index = i,
};
parent = clk_hw_get_parent_by_index(hw, i); parent = clk_hw_get_parent_by_index(hw, i);
if (!parent) if (!parent)
continue; continue;
...@@ -97,8 +112,9 @@ static int clk_factors_determine_rate(struct clk_hw *hw, ...@@ -97,8 +112,9 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
else else
parent_rate = clk_hw_get_rate(parent); parent_rate = clk_hw_get_rate(parent);
child_rate = clk_factors_round_rate(hw, req->rate, factors_req.parent_rate = parent_rate;
&parent_rate); factors->get_factors(&factors_req);
child_rate = factors_req.rate;
if (child_rate <= req->rate && child_rate > best_child_rate) { if (child_rate <= req->rate && child_rate > best_child_rate) {
best_parent = parent; best_parent = parent;
...@@ -120,13 +136,16 @@ static int clk_factors_determine_rate(struct clk_hw *hw, ...@@ -120,13 +136,16 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u8 n = 0, k = 0, m = 0, p = 0; struct factors_request req = {
.rate = rate,
.parent_rate = parent_rate,
};
u32 reg; u32 reg;
struct clk_factors *factors = to_clk_factors(hw); struct clk_factors *factors = to_clk_factors(hw);
struct clk_factors_config *config = factors->config; const struct clk_factors_config *config = factors->config;
unsigned long flags = 0; unsigned long flags = 0;
factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p); factors->get_factors(&req);
if (factors->lock) if (factors->lock)
spin_lock_irqsave(factors->lock, flags); spin_lock_irqsave(factors->lock, flags);
...@@ -135,10 +154,10 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -135,10 +154,10 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
reg = readl(factors->reg); reg = readl(factors->reg);
/* Set up the new factors - macros do not do anything if width is 0 */ /* Set up the new factors - macros do not do anything if width is 0 */
reg = FACTOR_SET(config->nshift, config->nwidth, reg, n); reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
reg = FACTOR_SET(config->kshift, config->kwidth, reg, k); reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
reg = FACTOR_SET(config->mshift, config->mwidth, reg, m); reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
reg = FACTOR_SET(config->pshift, config->pwidth, reg, p); reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);
/* Apply them now */ /* Apply them now */
writel(reg, factors->reg); writel(reg, factors->reg);
...@@ -155,7 +174,6 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -155,7 +174,6 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_factors_ops = { static const struct clk_ops clk_factors_ops = {
.determine_rate = clk_factors_determine_rate, .determine_rate = clk_factors_determine_rate,
.recalc_rate = clk_factors_recalc_rate, .recalc_rate = clk_factors_recalc_rate,
.round_rate = clk_factors_round_rate,
.set_rate = clk_factors_set_rate, .set_rate = clk_factors_set_rate,
}; };
...@@ -172,7 +190,7 @@ struct clk *sunxi_factors_register(struct device_node *node, ...@@ -172,7 +190,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
struct clk_hw *mux_hw = NULL; struct clk_hw *mux_hw = NULL;
const char *clk_name = node->name; const char *clk_name = node->name;
const char *parents[FACTORS_MAX_PARENTS]; const char *parents[FACTORS_MAX_PARENTS];
int i = 0; int ret, i = 0;
/* if we have a mux, we will have >1 parents */ /* if we have a mux, we will have >1 parents */
i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS); i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS);
...@@ -188,21 +206,22 @@ struct clk *sunxi_factors_register(struct device_node *node, ...@@ -188,21 +206,22 @@ struct clk *sunxi_factors_register(struct device_node *node,
factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
if (!factors) if (!factors)
return NULL; goto err_factors;
/* set up factors properties */ /* set up factors properties */
factors->reg = reg; factors->reg = reg;
factors->config = data->table; factors->config = data->table;
factors->get_factors = data->getter; factors->get_factors = data->getter;
factors->recalc = data->recalc;
factors->lock = lock; factors->lock = lock;
/* Add a gate if this factor clock can be gated */ /* Add a gate if this factor clock can be gated */
if (data->enable) { if (data->enable) {
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) { if (!gate)
kfree(factors); goto err_gate;
return NULL;
} factors->gate = gate;
/* set up gate properties */ /* set up gate properties */
gate->reg = reg; gate->reg = reg;
...@@ -214,11 +233,10 @@ struct clk *sunxi_factors_register(struct device_node *node, ...@@ -214,11 +233,10 @@ struct clk *sunxi_factors_register(struct device_node *node,
/* Add a mux if this factor clock can be muxed */ /* Add a mux if this factor clock can be muxed */
if (data->mux) { if (data->mux) {
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
if (!mux) { if (!mux)
kfree(factors); goto err_mux;
kfree(gate);
return NULL; factors->mux = mux;
}
/* set up gate properties */ /* set up gate properties */
mux->reg = reg; mux->reg = reg;
...@@ -233,11 +251,44 @@ struct clk *sunxi_factors_register(struct device_node *node, ...@@ -233,11 +251,44 @@ struct clk *sunxi_factors_register(struct device_node *node,
mux_hw, &clk_mux_ops, mux_hw, &clk_mux_ops,
&factors->hw, &clk_factors_ops, &factors->hw, &clk_factors_ops,
gate_hw, &clk_gate_ops, 0); gate_hw, &clk_gate_ops, 0);
if (IS_ERR(clk))
goto err_register;
if (!IS_ERR(clk)) { ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
of_clk_add_provider(node, of_clk_src_simple_get, clk); if (ret)
clk_register_clkdev(clk, clk_name, NULL); goto err_provider;
}
return clk; return clk;
err_provider:
/* TODO: The composite clock stuff will leak a bit here. */
clk_unregister(clk);
err_register:
kfree(mux);
err_mux:
kfree(gate);
err_gate:
kfree(factors);
err_factors:
return NULL;
}
void sunxi_factors_unregister(struct device_node *node, struct clk *clk)
{
struct clk_hw *hw = __clk_get_hw(clk);
struct clk_factors *factors;
const char *name;
if (!hw)
return;
factors = to_clk_factors(hw);
name = clk_hw_get_name(hw);
of_clk_del_provider(node);
/* TODO: The composite clock stuff will leak a bit here. */
clk_unregister(clk);
kfree(factors->mux);
kfree(factors->gate);
kfree(factors);
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define __MACH_SUNXI_CLK_FACTORS_H #define __MACH_SUNXI_CLK_FACTORS_H
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#define SUNXI_FACTORS_NOT_APPLICABLE (0) #define SUNXI_FACTORS_NOT_APPLICABLE (0)
...@@ -19,21 +18,36 @@ struct clk_factors_config { ...@@ -19,21 +18,36 @@ struct clk_factors_config {
u8 n_start; u8 n_start;
}; };
struct factors_request {
unsigned long rate;
unsigned long parent_rate;
u8 parent_index;
u8 n;
u8 k;
u8 m;
u8 p;
};
struct factors_data { struct factors_data {
int enable; int enable;
int mux; int mux;
int muxmask; int muxmask;
struct clk_factors_config *table; const struct clk_factors_config *table;
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); void (*getter)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
const char *name; const char *name;
}; };
struct clk_factors { struct clk_factors {
struct clk_hw hw; struct clk_hw hw;
void __iomem *reg; void __iomem *reg;
struct clk_factors_config *config; const struct clk_factors_config *config;
void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); void (*get_factors)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
spinlock_t *lock; spinlock_t *lock;
/* for cleanup */
struct clk_mux *mux;
struct clk_gate *gate;
}; };
struct clk *sunxi_factors_register(struct device_node *node, struct clk *sunxi_factors_register(struct device_node *node,
...@@ -41,4 +55,6 @@ struct clk *sunxi_factors_register(struct device_node *node, ...@@ -41,4 +55,6 @@ struct clk *sunxi_factors_register(struct device_node *node,
spinlock_t *lock, spinlock_t *lock,
void __iomem *reg); void __iomem *reg);
void sunxi_factors_unregister(struct device_node *node, struct clk *clk);
#endif #endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -28,17 +29,16 @@ ...@@ -28,17 +29,16 @@
* rate = (parent_rate >> p) / (m + 1); * rate = (parent_rate >> p) / (m + 1);
*/ */
static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate, static void sun4i_a10_get_mod0_factors(struct factors_request *req)
u8 *n, u8 *k, u8 *m, u8 *p)
{ {
u8 div, calcm, calcp; u8 div, calcm, calcp;
/* These clocks can only divide, so we will never be able to achieve /* These clocks can only divide, so we will never be able to achieve
* frequencies higher than the parent frequency */ * frequencies higher than the parent frequency */
if (*freq > parent_rate) if (req->rate > req->parent_rate)
*freq = parent_rate; req->rate = req->parent_rate;
div = DIV_ROUND_UP(parent_rate, *freq); div = DIV_ROUND_UP(req->parent_rate, req->rate);
if (div < 16) if (div < 16)
calcp = 0; calcp = 0;
...@@ -51,18 +51,13 @@ static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate, ...@@ -51,18 +51,13 @@ static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate,
calcm = DIV_ROUND_UP(div, 1 << calcp); calcm = DIV_ROUND_UP(div, 1 << calcp);
*freq = (parent_rate >> calcp) / calcm; req->rate = (req->parent_rate >> calcp) / calcm;
req->m = calcm - 1;
/* we were called to round the frequency, we can now return */ req->p = calcp;
if (n == NULL)
return;
*m = calcm - 1;
*p = calcp;
} }
/* user manual says "n" but it's really "p" */ /* user manual says "n" but it's really "p" */
static struct clk_factors_config sun4i_a10_mod0_config = { static const struct clk_factors_config sun4i_a10_mod0_config = {
.mshift = 0, .mshift = 0,
.mwidth = 4, .mwidth = 4,
.pshift = 16, .pshift = 16,
......
...@@ -98,6 +98,8 @@ static void __init sunxi_simple_gates_init(struct device_node *node) ...@@ -98,6 +98,8 @@ static void __init sunxi_simple_gates_init(struct device_node *node)
sunxi_simple_gates_setup(node, NULL, 0); sunxi_simple_gates_setup(node, NULL, 0);
} }
CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk", CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk",
sunxi_simple_gates_init); sunxi_simple_gates_init);
CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk", CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk",
...@@ -130,6 +132,8 @@ CLK_OF_DECLARE(sun8i_a23_apb2, "allwinner,sun8i-a23-apb2-gates-clk", ...@@ -130,6 +132,8 @@ CLK_OF_DECLARE(sun8i_a23_apb2, "allwinner,sun8i-a23-apb2-gates-clk",
sunxi_simple_gates_init); sunxi_simple_gates_init);
CLK_OF_DECLARE(sun8i_a33_ahb1, "allwinner,sun8i-a33-ahb1-gates-clk", CLK_OF_DECLARE(sun8i_a33_ahb1, "allwinner,sun8i-a33-ahb1-gates-clk",
sunxi_simple_gates_init); sunxi_simple_gates_init);
CLK_OF_DECLARE(sun8i_a83t_apb0, "allwinner,sun8i-a83t-apb0-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_ahb0, "allwinner,sun9i-a80-ahb0-gates-clk", CLK_OF_DECLARE(sun9i_a80_ahb0, "allwinner,sun9i-a80-ahb0-gates-clk",
sunxi_simple_gates_init); sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_ahb1, "allwinner,sun9i-a80-ahb1-gates-clk", CLK_OF_DECLARE(sun9i_a80_ahb1, "allwinner,sun9i-a80-ahb1-gates-clk",
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -87,7 +86,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) ...@@ -87,7 +86,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
clk_parent, 0, reg, i, clk_parent, 0, reg, i,
0, NULL); 0, NULL);
WARN_ON(IS_ERR(clk_data->clks[i])); WARN_ON(IS_ERR(clk_data->clks[i]));
clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
j++; j++;
} }
......
...@@ -8,211 +8,97 @@ ...@@ -8,211 +8,97 @@
* *
*/ */
#include <linux/bitops.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h>
#define SUN6I_AR100_MAX_PARENTS 4 #include "clk-factors.h"
#define SUN6I_AR100_SHIFT_MASK 0x3
#define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK
#define SUN6I_AR100_SHIFT_SHIFT 4
#define SUN6I_AR100_DIV_MASK 0x1f
#define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1)
#define SUN6I_AR100_DIV_SHIFT 8
#define SUN6I_AR100_MUX_MASK 0x3
#define SUN6I_AR100_MUX_SHIFT 16
struct ar100_clk {
struct clk_hw hw;
void __iomem *reg;
};
static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw)
{
return container_of(hw, struct ar100_clk, hw);
}
static unsigned long ar100_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct ar100_clk *clk = to_ar100_clk(hw);
u32 val = readl(clk->reg);
int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK;
int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK;
return (parent_rate >> shift) / (div + 1);
}
static int ar100_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
int nparents = clk_hw_get_num_parents(hw);
long best_rate = -EINVAL;
int i;
req->best_parent_hw = NULL;
for (i = 0; i < nparents; i++) {
unsigned long parent_rate;
unsigned long tmp_rate;
struct clk_hw *parent;
unsigned long div;
int shift;
parent = clk_hw_get_parent_by_index(hw, i);
parent_rate = clk_hw_get_rate(parent);
div = DIV_ROUND_UP(parent_rate, req->rate);
/*
* The AR100 clk contains 2 divisors:
* - one power of 2 divisor
* - one regular divisor
*
* First check if we can safely shift (or divide by a power
* of 2) without losing precision on the requested rate.
*/
shift = ffs(div) - 1;
if (shift > SUN6I_AR100_SHIFT_MAX)
shift = SUN6I_AR100_SHIFT_MAX;
div >>= shift;
/*
* Then if the divisor is still bigger than what the HW
* actually supports, use a bigger shift (or power of 2
* divider) value and accept to lose some precision.
*/
while (div > SUN6I_AR100_DIV_MAX) {
shift++;
div >>= 1;
if (shift > SUN6I_AR100_SHIFT_MAX)
break;
}
/*
* If the shift value (or power of 2 divider) is bigger
* than what the HW actually support, skip this parent.
*/
if (shift > SUN6I_AR100_SHIFT_MAX)
continue;
tmp_rate = (parent_rate >> shift) / div;
if (!req->best_parent_hw || tmp_rate > best_rate) {
req->best_parent_hw = parent;
req->best_parent_rate = parent_rate;
best_rate = tmp_rate;
}
}
if (best_rate < 0)
return best_rate;
req->rate = best_rate;
return 0;
}
static int ar100_set_parent(struct clk_hw *hw, u8 index)
{
struct ar100_clk *clk = to_ar100_clk(hw);
u32 val = readl(clk->reg);
if (index >= SUN6I_AR100_MAX_PARENTS)
return -EINVAL;
val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT);
val |= (index << SUN6I_AR100_MUX_SHIFT);
writel(val, clk->reg);
return 0;
}
static u8 ar100_get_parent(struct clk_hw *hw) /**
{ * sun6i_get_ar100_factors - Calculates factors p, m for AR100
struct ar100_clk *clk = to_ar100_clk(hw); *
return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) & * AR100 rate is calculated as follows
SUN6I_AR100_MUX_MASK; * rate = (parent_rate >> p) / (m + 1);
} */
static void sun6i_get_ar100_factors(struct factors_request *req)
static int ar100_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{ {
unsigned long div = parent_rate / rate; unsigned long div;
struct ar100_clk *clk = to_ar100_clk(hw);
u32 val = readl(clk->reg);
int shift; int shift;
if (parent_rate % rate) /* clock only divides */
return -EINVAL; if (req->rate > req->parent_rate)
req->rate = req->parent_rate;
shift = ffs(div) - 1; div = DIV_ROUND_UP(req->parent_rate, req->rate);
if (shift > SUN6I_AR100_SHIFT_MAX)
shift = SUN6I_AR100_SHIFT_MAX;
div >>= shift; if (div < 32)
shift = 0;
else if (div >> 1 < 32)
shift = 1;
else if (div >> 2 < 32)
shift = 2;
else
shift = 3;
if (div > SUN6I_AR100_DIV_MAX) div >>= shift;
return -EINVAL;
val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) | if (div > 32)
(SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT)); div = 32;
val |= (shift << SUN6I_AR100_SHIFT_SHIFT) |
(div << SUN6I_AR100_DIV_SHIFT);
writel(val, clk->reg);
return 0; req->rate = (req->parent_rate >> shift) / div;
req->m = div - 1;
req->p = shift;
} }
static struct clk_ops ar100_ops = { static const struct clk_factors_config sun6i_ar100_config = {
.recalc_rate = ar100_recalc_rate, .mwidth = 5,
.determine_rate = ar100_determine_rate, .mshift = 8,
.set_parent = ar100_set_parent, .pwidth = 2,
.get_parent = ar100_get_parent, .pshift = 4,
.set_rate = ar100_set_rate,
}; };
static const struct factors_data sun6i_ar100_data = {
.mux = 16,
.muxmask = GENMASK(1, 0),
.table = &sun6i_ar100_config,
.getter = sun6i_get_ar100_factors,
};
static DEFINE_SPINLOCK(sun6i_ar100_lock);
static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
{ {
const char *parents[SUN6I_AR100_MAX_PARENTS];
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const char *clk_name = np->name;
struct clk_init_data init;
struct ar100_clk *ar100;
struct resource *r; struct resource *r;
void __iomem *reg;
struct clk *clk; struct clk *clk;
unsigned int nparents;
ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
if (!ar100)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ar100->reg = devm_ioremap_resource(&pdev->dev, r); reg = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(ar100->reg)) if (IS_ERR(reg))
return PTR_ERR(ar100->reg); return PTR_ERR(reg);
nparents = of_clk_get_parent_count(np); clk = sunxi_factors_register(np, &sun6i_ar100_data, &sun6i_ar100_lock,
if (nparents > SUN6I_AR100_MAX_PARENTS) reg);
nparents = SUN6I_AR100_MAX_PARENTS; if (!clk)
return -ENOMEM;
of_clk_parent_fill(np, parents, nparents);
of_property_read_string(np, "clock-output-names", &clk_name); platform_set_drvdata(pdev, clk);
init.name = clk_name; return 0;
init.ops = &ar100_ops; }
init.parent_names = parents;
init.num_parents = nparents;
init.flags = 0;
ar100->hw.init = &init; static int sun6i_a31_ar100_clk_remove(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct clk *clk = platform_get_drvdata(pdev);
clk = clk_register(&pdev->dev, &ar100->hw); sunxi_factors_unregister(np, clk);
if (IS_ERR(clk))
return PTR_ERR(clk);
return of_clk_add_provider(np, of_clk_src_simple_get, clk); return 0;
} }
static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = {
...@@ -227,6 +113,7 @@ static struct platform_driver sun6i_a31_ar100_clk_driver = { ...@@ -227,6 +113,7 @@ static struct platform_driver sun6i_a31_ar100_clk_driver = {
.of_match_table = sun6i_a31_ar100_clk_dt_ids, .of_match_table = sun6i_a31_ar100_clk_dt_ids,
}, },
.probe = sun6i_a31_ar100_clk_probe, .probe = sun6i_a31_ar100_clk_probe,
.remove = sun6i_a31_ar100_clk_remove,
}; };
module_platform_driver(sun6i_a31_ar100_clk_driver); module_platform_driver(sun6i_a31_ar100_clk_driver);
......
...@@ -36,7 +36,7 @@ static struct clk *sun8i_a23_apb0_register(struct device_node *node, ...@@ -36,7 +36,7 @@ static struct clk *sun8i_a23_apb0_register(struct device_node *node,
/* The A23 APB0 clock is a standard 2 bit wide divider clock */ /* The A23 APB0 clock is a standard 2 bit wide divider clock */
clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg, clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); 0, 2, 0, NULL);
if (IS_ERR(clk)) if (IS_ERR(clk))
return clk; return clk;
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -110,3 +109,5 @@ static void __init sun8i_h3_bus_gates_init(struct device_node *node) ...@@ -110,3 +109,5 @@ static void __init sun8i_h3_bus_gates_init(struct device_node *node)
CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk", CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
sun8i_h3_bus_gates_init); sun8i_h3_bus_gates_init);
CLK_OF_DECLARE(sun8i_a83t_bus_gates, "allwinner,sun8i-a83t-bus-gates-clk",
sun8i_h3_bus_gates_init);
...@@ -15,74 +15,99 @@ ...@@ -15,74 +15,99 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include "clk-factors.h" #define SUN8I_MBUS_ENABLE 31
#define SUN8I_MBUS_MUX_SHIFT 24
#define SUN8I_MBUS_MUX_MASK 0x3
#define SUN8I_MBUS_DIV_SHIFT 0
#define SUN8I_MBUS_DIV_WIDTH 3
#define SUN8I_MBUS_MAX_PARENTS 4
/** static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
* sun8i_a23_get_mbus_factors() - calculates m factor for MBUS clocks
* MBUS rate is calculated as follows
* rate = parent_rate / (m + 1);
*/
static void sun8i_a23_get_mbus_factors(u32 *freq, u32 parent_rate, static void __init sun8i_a23_mbus_setup(struct device_node *node)
u8 *n, u8 *k, u8 *m, u8 *p)
{ {
u8 div; int num_parents = of_clk_get_parent_count(node);
const char *parents[num_parents];
/* const char *clk_name = node->name;
* These clocks can only divide, so we will never be able to struct resource res;
* achieve frequencies higher than the parent frequency struct clk_divider *div;
*/ struct clk_gate *gate;
if (*freq > parent_rate) struct clk_mux *mux;
*freq = parent_rate; struct clk *clk;
void __iomem *reg;
div = DIV_ROUND_UP(parent_rate, *freq); int err;
if (div > 8) reg = of_io_request_and_map(node, 0, of_node_full_name(node));
div = 8; if (!reg) {
pr_err("Could not get registers for sun8i-mbus-clk\n");
return;
}
*freq = parent_rate / div; div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
goto err_unmap;
/* we were called to round the frequency, we can now return */ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (m == NULL) if (!mux)
return; goto err_free_div;
*m = div - 1; gate = kzalloc(sizeof(*gate), GFP_KERNEL);
} if (!gate)
goto err_free_mux;
static struct clk_factors_config sun8i_a23_mbus_config = { of_property_read_string(node, "clock-output-names", &clk_name);
.mshift = 0, of_clk_parent_fill(node, parents, num_parents);
.mwidth = 3,
};
static const struct factors_data sun8i_a23_mbus_data __initconst = { gate->reg = reg;
.enable = 31, gate->bit_idx = SUN8I_MBUS_ENABLE;
.mux = 24, gate->lock = &sun8i_a23_mbus_lock;
.muxmask = BIT(1) | BIT(0),
.table = &sun8i_a23_mbus_config,
.getter = sun8i_a23_get_mbus_factors,
};
static DEFINE_SPINLOCK(sun8i_a23_mbus_lock); div->reg = reg;
div->shift = SUN8I_MBUS_DIV_SHIFT;
div->width = SUN8I_MBUS_DIV_WIDTH;
div->lock = &sun8i_a23_mbus_lock;
static void __init sun8i_a23_mbus_setup(struct device_node *node) mux->reg = reg;
{ mux->shift = SUN8I_MBUS_MUX_SHIFT;
struct clk *mbus; mux->mask = SUN8I_MBUS_MUX_MASK;
void __iomem *reg; mux->lock = &sun8i_a23_mbus_lock;
reg = of_iomap(node, 0); clk = clk_register_composite(NULL, clk_name, parents, num_parents,
if (!reg) { &mux->hw, &clk_mux_ops,
pr_err("Could not get registers for a23-mbus-clk\n"); &div->hw, &clk_divider_ops,
return; &gate->hw, &clk_gate_ops,
} 0);
if (IS_ERR(clk))
goto err_free_gate;
mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data, err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
&sun8i_a23_mbus_lock, reg); if (err)
goto err_unregister_clk;
/* The MBUS clocks needs to be always enabled */ /* The MBUS clocks needs to be always enabled */
__clk_get(mbus); __clk_get(clk);
clk_prepare_enable(mbus); clk_prepare_enable(clk);
return;
err_unregister_clk:
/* TODO: The composite clock stuff will leak a bit here. */
clk_unregister(clk);
err_free_gate:
kfree(gate);
err_free_mux:
kfree(mux);
err_free_div:
kfree(div);
err_unmap:
iounmap(reg);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
} }
CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup); CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup);
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -32,15 +33,14 @@ ...@@ -32,15 +33,14 @@
* p and m are named div1 and div2 in Allwinner's SDK * p and m are named div1 and div2 in Allwinner's SDK
*/ */
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, static void sun9i_a80_get_pll4_factors(struct factors_request *req)
u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret)
{ {
int n; int n;
int m = 1; int m = 1;
int p = 1; int p = 1;
/* Normalize value to a 6 MHz multiple (24 MHz / 4) */ /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
n = DIV_ROUND_UP(*freq, 6000000); n = DIV_ROUND_UP(req->rate, 6000000);
/* If n is too large switch to steps of 12 MHz */ /* If n is too large switch to steps of 12 MHz */
if (n > 255) { if (n > 255) {
...@@ -60,18 +60,13 @@ static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, ...@@ -60,18 +60,13 @@ static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
else if (n < 12) else if (n < 12)
n = 12; n = 12;
*freq = ((24000000 * n) >> p) / (m + 1); req->rate = ((24000000 * n) >> p) / (m + 1);
req->n = n;
/* we were called to round the frequency, we can now return */ req->m = m;
if (n_ret == NULL) req->p = p;
return;
*n_ret = n;
*m_ret = m;
*p_ret = p;
} }
static struct clk_factors_config sun9i_a80_pll4_config = { static const struct clk_factors_config sun9i_a80_pll4_config = {
.mshift = 18, .mshift = 18,
.mwidth = 1, .mwidth = 1,
.nshift = 8, .nshift = 8,
...@@ -111,30 +106,24 @@ CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_se ...@@ -111,30 +106,24 @@ CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_se
* rate = parent_rate / (m + 1); * rate = parent_rate / (m + 1);
*/ */
static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate, static void sun9i_a80_get_gt_factors(struct factors_request *req)
u8 *n, u8 *k, u8 *m, u8 *p)
{ {
u32 div; u32 div;
if (parent_rate < *freq) if (req->parent_rate < req->rate)
*freq = parent_rate; req->rate = req->parent_rate;
div = DIV_ROUND_UP(parent_rate, *freq); div = DIV_ROUND_UP(req->parent_rate, req->rate);
/* maximum divider is 4 */ /* maximum divider is 4 */
if (div > 4) if (div > 4)
div = 4; div = 4;
*freq = parent_rate / div; req->rate = req->parent_rate / div;
req->m = div;
/* we were called to round the frequency, we can now return */
if (!m)
return;
*m = div;
} }
static struct clk_factors_config sun9i_a80_gt_config = { static const struct clk_factors_config sun9i_a80_gt_config = {
.mshift = 0, .mshift = 0,
.mwidth = 2, .mwidth = 2,
}; };
...@@ -176,30 +165,24 @@ CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); ...@@ -176,30 +165,24 @@ CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
* rate = parent_rate >> p; * rate = parent_rate >> p;
*/ */
static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate, static void sun9i_a80_get_ahb_factors(struct factors_request *req)
u8 *n, u8 *k, u8 *m, u8 *p)
{ {
u32 _p; u32 _p;
if (parent_rate < *freq) if (req->parent_rate < req->rate)
*freq = parent_rate; req->rate = req->parent_rate;
_p = order_base_2(DIV_ROUND_UP(parent_rate, *freq)); _p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
/* maximum p is 3 */ /* maximum p is 3 */
if (_p > 3) if (_p > 3)
_p = 3; _p = 3;
*freq = parent_rate >> _p; req->rate = req->parent_rate >> _p;
req->p = _p;
/* we were called to round the frequency, we can now return */
if (!p)
return;
*p = _p;
} }
static struct clk_factors_config sun9i_a80_ahb_config = { static const struct clk_factors_config sun9i_a80_ahb_config = {
.pshift = 0, .pshift = 0,
.pwidth = 2, .pwidth = 2,
}; };
...@@ -262,34 +245,25 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_se ...@@ -262,34 +245,25 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_se
* rate = (parent_rate >> p) / (m + 1); * rate = (parent_rate >> p) / (m + 1);
*/ */
static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate, static void sun9i_a80_get_apb1_factors(struct factors_request *req)
u8 *n, u8 *k, u8 *m, u8 *p)
{ {
u32 div; u32 div;
u8 calcm, calcp;
if (parent_rate < *freq) if (req->parent_rate < req->rate)
*freq = parent_rate; req->rate = req->parent_rate;
div = DIV_ROUND_UP(parent_rate, *freq); div = DIV_ROUND_UP(req->parent_rate, req->rate);
/* Highest possible divider is 256 (p = 3, m = 31) */ /* Highest possible divider is 256 (p = 3, m = 31) */
if (div > 256) if (div > 256)
div = 256; div = 256;
calcp = order_base_2(div); req->p = order_base_2(div);
calcm = (parent_rate >> calcp) - 1; req->m = (req->parent_rate >> req->p) - 1;
*freq = (parent_rate >> calcp) / (calcm + 1); req->rate = (req->parent_rate >> req->p) / (req->m + 1);
/* we were called to round the frequency, we can now return */
if (n == NULL)
return;
*m = calcm;
*p = calcp;
} }
static struct clk_factors_config sun9i_a80_apb1_config = { static const struct clk_factors_config sun9i_a80_apb1_config = {
.mshift = 0, .mshift = 0,
.mwidth = 5, .mwidth = 5,
.pshift = 16, .pshift = 16,
......
This diff is collapsed.
...@@ -216,6 +216,18 @@ static void __init sun8i_a23_usb_setup(struct device_node *node) ...@@ -216,6 +216,18 @@ static void __init sun8i_a23_usb_setup(struct device_node *node)
} }
CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup); CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup);
static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
.clk_mask = BIT(19) | BIT(18) | BIT(17) | BIT(16) |
BIT(11) | BIT(10) | BIT(9) | BIT(8),
.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
};
static void __init sun8i_h3_usb_setup(struct device_node *node)
{
sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);
static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = { static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
.clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1), .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
.reset_mask = BIT(19) | BIT(18) | BIT(17), .reset_mask = BIT(19) | BIT(18) | BIT(17),
...@@ -243,15 +255,3 @@ static void __init sun9i_a80_usb_phy_setup(struct device_node *node) ...@@ -243,15 +255,3 @@ static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock); sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
} }
CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup); CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
.clk_mask = BIT(19) | BIT(18) | BIT(17) | BIT(16) |
BIT(11) | BIT(10) | BIT(9) | BIT(8),
.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
};
static void __init sun8i_h3_usb_setup(struct device_node *node)
{
sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment