Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ Required properties:
	"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
	"allwinner,sun4i-a10-axi-clk" - for the AXI clock
	"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-ahb-clk" - for the AHB clock
	"allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13
@@ -39,12 +40,14 @@ Required properties:
	"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
	"allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
	"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,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
	"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,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-h3-apb0-gates-clk" - for the APB0 gates on H3
	"allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80
	"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
	"allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80
@@ -57,6 +60,7 @@ Required properties:
	"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,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,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
	"allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10
+1 −2
Original line number Diff line number Diff line
@@ -15,9 +15,9 @@
 */

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>

#define SUNXI_OSC24M_GATE	0

@@ -61,7 +61,6 @@ static void __init sun4i_osc_clk_setup(struct device_node *node)
		goto err_free_gate;

	of_clk_add_provider(node, of_clk_src_simple_get, clk);
	clk_register_clkdev(clk, clk_name, NULL);

	return;

+0 −2
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
 */

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
@@ -107,7 +106,6 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
		goto iounmap_reg;

	of_clk_add_provider(node, of_clk_src_simple_get, clk);
	clk_register_clkdev(clk, clk_name, NULL);

	return;

+87 −36
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
	u32 reg;
	unsigned long rate;
	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 */
	reg = readl(factors->reg);
@@ -63,18 +63,28 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
	if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
		p = FACTOR_GET(config->pshift, config->pwidth, reg);

	/* Calculate the rate */
	rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1);
	if (factors->recalc) {
		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;

		factors->recalc(&factors_req);

		return factors_req.rate;
	}

static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
				   unsigned long *parent_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;
}
@@ -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,
				      struct clk_rate_request *req)
{
	struct clk_factors *factors = to_clk_factors(hw);
	struct clk_hw *parent, *best_parent = NULL;
	int i, num_parents;
	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,
	/* find the parent that can help provide the fastest rate <= rate */
	num_parents = clk_hw_get_num_parents(hw);
	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);
		if (!parent)
			continue;
@@ -97,8 +112,9 @@ static int clk_factors_determine_rate(struct clk_hw *hw,
		else
			parent_rate = clk_hw_get_rate(parent);

		child_rate = clk_factors_round_rate(hw, req->rate,
						    &parent_rate);
		factors_req.parent_rate = parent_rate;
		factors->get_factors(&factors_req);
		child_rate = factors_req.rate;

		if (child_rate <= req->rate && child_rate > best_child_rate) {
			best_parent = parent;
@@ -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,
				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;
	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;

	factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p);
	factors->get_factors(&req);

	if (factors->lock)
		spin_lock_irqsave(factors->lock, flags);
@@ -135,10 +154,10 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
	reg = readl(factors->reg);

	/* 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->kshift, config->kwidth, reg, k);
	reg = FACTOR_SET(config->mshift, config->mwidth, reg, m);
	reg = FACTOR_SET(config->pshift, config->pwidth, reg, p);
	reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
	reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
	reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
	reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);

	/* Apply them now */
	writel(reg, factors->reg);
@@ -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 = {
	.determine_rate = clk_factors_determine_rate,
	.recalc_rate = clk_factors_recalc_rate,
	.round_rate = clk_factors_round_rate,
	.set_rate = clk_factors_set_rate,
};

@@ -172,7 +190,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
	struct clk_hw *mux_hw = NULL;
	const char *clk_name = node->name;
	const char *parents[FACTORS_MAX_PARENTS];
	int i = 0;
	int ret, i = 0;

	/* if we have a mux, we will have >1 parents */
	i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS);
@@ -188,21 +206,22 @@ struct clk *sunxi_factors_register(struct device_node *node,

	factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
	if (!factors)
		return NULL;
		goto err_factors;

	/* set up factors properties */
	factors->reg = reg;
	factors->config = data->table;
	factors->get_factors = data->getter;
	factors->recalc = data->recalc;
	factors->lock = lock;

	/* Add a gate if this factor clock can be gated */
	if (data->enable) {
		gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
		if (!gate) {
			kfree(factors);
			return NULL;
		}
		if (!gate)
			goto err_gate;

		factors->gate = gate;

		/* set up gate properties */
		gate->reg = reg;
@@ -214,11 +233,10 @@ struct clk *sunxi_factors_register(struct device_node *node,
	/* Add a mux if this factor clock can be muxed */
	if (data->mux) {
		mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
		if (!mux) {
			kfree(factors);
			kfree(gate);
			return NULL;
		}
		if (!mux)
			goto err_mux;

		factors->mux = mux;

		/* set up gate properties */
		mux->reg = reg;
@@ -233,11 +251,44 @@ struct clk *sunxi_factors_register(struct device_node *node,
			mux_hw, &clk_mux_ops,
			&factors->hw, &clk_factors_ops,
			gate_hw, &clk_gate_ops, 0);
	if (IS_ERR(clk))
		goto err_register;

	if (!IS_ERR(clk)) {
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
		clk_register_clkdev(clk, clk_name, NULL);
	}
	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
	if (ret)
		goto err_provider;

	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);
}
+21 −5
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@
#define __MACH_SUNXI_CLK_FACTORS_H

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h>

#define SUNXI_FACTORS_NOT_APPLICABLE	(0)
@@ -19,21 +18,36 @@ struct clk_factors_config {
	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 {
	int enable;
	int mux;
	int muxmask;
	struct clk_factors_config *table;
	void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
	const struct clk_factors_config *table;
	void (*getter)(struct factors_request *req);
	void (*recalc)(struct factors_request *req);
	const char *name;
};

struct clk_factors {
	struct clk_hw hw;
	void __iomem *reg;
	struct clk_factors_config *config;
	void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p);
	const struct clk_factors_config *config;
	void (*get_factors)(struct factors_request *req);
	void (*recalc)(struct factors_request *req);
	spinlock_t *lock;
	/* for cleanup */
	struct clk_mux *mux;
	struct clk_gate *gate;
};

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,
				   void __iomem *reg);

void sunxi_factors_unregister(struct device_node *node, struct clk *clk);

#endif
Loading