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

Commit 3cc5aba4 authored by Mike Turquette's avatar Mike Turquette
Browse files

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

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

Allwinner clocks additions for 3.17

This pull request adds support for the clocks found in the newly supported
Allwinner A23 clocks.
parents 9ae14005 6c1d66f0
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -9,11 +9,13 @@ Required properties:
	"allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
	"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
	"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
	"allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
	"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
	"allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
	"allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
	"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-axi-gates-clk" - for the AXI gates
	"allwinner,sun4i-a10-ahb-clk" - for the AHB clock
	"allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
@@ -23,13 +25,16 @@ Required properties:
	"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
	"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
	"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
	"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
	"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
	"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
	"allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
	"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,sun4i-a10-apb1-clk" - for the APB1 clock
	"allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
	"allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
@@ -37,8 +42,10 @@ Required properties:
	"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
	"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
	"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
	"allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23
	"allwinner,sun6i-a31-apb2-div-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,sun4i-a10-mod0-clk" - for the module 0 family of clocks
	"allwinner,sun7i-a20-out-clk" - for the external output clocks
	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
+3 −1
Original line number Diff line number Diff line
@@ -6,4 +6,6 @@ obj-y += clk-sunxi.o clk-factors.o
obj-y += clk-a10-hosc.o
obj-y += clk-a20-gmac.o

obj-$(CONFIG_MFD_SUN6I_PRCM) += clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
	clk-sun8i-apb0.o
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
		p = FACTOR_GET(config->pshift, config->pwidth, reg);

	/* Calculate the rate */
	rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
	rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1);

	return rate;
}
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ struct clk_factors_config {
	u8 mwidth;
	u8 pshift;
	u8 pwidth;
	u8 n_start;
};

struct clk_factors {
+44 −32
Original line number Diff line number Diff line
@@ -9,23 +9,53 @@
 */

#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>

#define SUN6I_APB0_GATES_MAX_SIZE	32

struct gates_data {
	DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE);
};

static const struct gates_data sun6i_a31_apb0_gates __initconst = {
	.mask = {0x7F},
};

static const struct gates_data sun8i_a23_apb0_gates __initconst = {
	.mask = {0x5D},
};

const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
	{ .compatible = "allwinner,sun6i-a31-apb0-gates-clk", .data = &sun6i_a31_apb0_gates },
	{ .compatible = "allwinner,sun8i-a23-apb0-gates-clk", .data = &sun8i_a23_apb0_gates },
	{ /* sentinel */ }
};

static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct clk_onecell_data *clk_data;
	const struct of_device_id *device;
	const struct gates_data *data;
	const char *clk_parent;
	const char *clk_name;
	struct resource *r;
	void __iomem *reg;
	int gate_id;
	int ngates;
	int i;
	int j = 0;

	if (!np)
		return -ENODEV;

	device = of_match_device(sun6i_a31_apb0_gates_clk_dt_ids, &pdev->dev);
	if (!device)
		return -ENODEV;
	data = device->data;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	reg = devm_ioremap_resource(&pdev->dev, r);
@@ -36,54 +66,36 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
	if (!clk_parent)
		return -EINVAL;

	ngates = of_property_count_strings(np, "clock-output-names");
	if (ngates < 0)
		return ngates;

	if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE)
		return -EINVAL;

	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
				GFP_KERNEL);
	if (!clk_data)
		return -ENOMEM;

	clk_data->clks = devm_kzalloc(&pdev->dev,
				      SUN6I_APB0_GATES_MAX_SIZE *
				      sizeof(struct clk *),
				      GFP_KERNEL);
	/* Worst-case size approximation and memory allocation */
	ngates = find_last_bit(data->mask, SUN6I_APB0_GATES_MAX_SIZE);
	clk_data->clks = devm_kcalloc(&pdev->dev, (ngates + 1),
				      sizeof(struct clk *), GFP_KERNEL);
	if (!clk_data->clks)
		return -ENOMEM;

	for (i = 0; i < ngates; i++) {
	for_each_set_bit(i, data->mask, SUN6I_APB0_GATES_MAX_SIZE) {
		of_property_read_string_index(np, "clock-output-names",
					      i, &clk_name);

		gate_id = i;
		of_property_read_u32_index(np, "clock-indices", i, &gate_id);

		WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE);
		if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE)
			continue;
					      j, &clk_name);

		clk_data->clks[gate_id] = clk_register_gate(&pdev->dev,
							    clk_name,
							    clk_parent, 0,
							    reg, gate_id,
		clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
						      clk_parent, 0, reg, i,
						      0, NULL);
		WARN_ON(IS_ERR(clk_data->clks[gate_id]));
		WARN_ON(IS_ERR(clk_data->clks[i]));
		clk_register_clkdev(clk_data->clks[i], clk_name, NULL);

		j++;
	}

	clk_data->clk_num = ngates;
	clk_data->clk_num = ngates + 1;

	return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
}

const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
	{ .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
	{ /* sentinel */ }
};

static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
	.driver = {
		.name = "sun6i-a31-apb0-gates-clk",
Loading