cregit-Linux how code gets into the kernel

Release 4.7 drivers/clk/sunxi/clk-sun4i-display.c

/*
 * Copyright 2015 Maxime Ripard
 *
 * Maxime Ripard <maxime.ripard@free-electrons.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/clk-provider.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>


struct sun4i_a10_display_clk_data {
	
bool	has_div;
	
u8	num_rst;
	
u8	parents;

	
u8	offset_en;
	
u8	offset_div;
	
u8	offset_mux;
	
u8	offset_rst;

	
u8	width_div;
	
u8	width_mux;

	
u32	flags;
};


struct reset_data {
	
void __iomem			*reg;
	
spinlock_t			*lock;
	
struct reset_controller_dev	rcdev;
	
u8				offset;
};

static DEFINE_SPINLOCK(sun4i_a10_display_lock);


static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev) { return container_of(rcdev, struct reset_data, rcdev); }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard25100.00%1100.00%
Total25100.00%1100.00%

;
static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev, unsigned long id) { struct reset_data *data = rcdev_to_reset_data(rcdev); unsigned long flags; u32 reg; spin_lock_irqsave(data->lock, flags); reg = readl(data->reg); writel(reg & ~BIT(data->offset + id), data->reg); spin_unlock_irqrestore(data->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard81100.00%1100.00%
Total81100.00%1100.00%


static int sun4i_a10_display_deassert(struct reset_controller_dev *rcdev, unsigned long id) { struct reset_data *data = rcdev_to_reset_data(rcdev); unsigned long flags; u32 reg; spin_lock_irqsave(data->lock, flags); reg = readl(data->reg); writel(reg | BIT(data->offset + id), data->reg); spin_unlock_irqrestore(data->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard80100.00%1100.00%
Total80100.00%1100.00%


static int sun4i_a10_display_status(struct reset_controller_dev *rcdev, unsigned long id) { struct reset_data *data = rcdev_to_reset_data(rcdev); return !(readl(data->reg) & BIT(data->offset + id)); }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard45100.00%1100.00%
Total45100.00%1100.00%

static const struct reset_control_ops sun4i_a10_display_reset_ops = { .assert = sun4i_a10_display_assert, .deassert = sun4i_a10_display_deassert, .status = sun4i_a10_display_status, };
static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *spec) { /* We only have a single reset signal */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard21100.00%1100.00%
Total21100.00%1100.00%


static void __init sun4i_a10_display_init(struct device_node *node, const struct sun4i_a10_display_clk_data *data) { const char *parents[4]; const char *clk_name = node->name; struct reset_data *reset_data; struct clk_divider *div = NULL; struct clk_gate *gate; struct resource res; struct clk_mux *mux; void __iomem *reg; struct clk *clk; int ret; of_property_read_string(node, "clock-output-names", &clk_name); reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { pr_err("%s: Could not map the clock registers\n", clk_name); return; } ret = of_clk_parent_fill(node, parents, data->parents); if (ret != data->parents) { pr_err("%s: Could not retrieve the parents\n", clk_name); goto unmap; } mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) goto unmap; mux->reg = reg; mux->shift = data->offset_mux; mux->mask = (1 << data->width_mux) - 1; mux->lock = &sun4i_a10_display_lock; gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) goto free_mux; gate->reg = reg; gate->bit_idx = data->offset_en; gate->lock = &sun4i_a10_display_lock; if (data->has_div) { div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) goto free_gate; div->reg = reg; div->shift = data->offset_div; div->width = data->width_div; div->lock = &sun4i_a10_display_lock; } clk = clk_register_composite(NULL, clk_name, parents, data->parents, &mux->hw, &clk_mux_ops, data->has_div ? &div->hw : NULL, data->has_div ? &clk_divider_ops : NULL, &gate->hw, &clk_gate_ops, data->flags); if (IS_ERR(clk)) { pr_err("%s: Couldn't register the clock\n", clk_name); goto free_div; } ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); if (ret) { pr_err("%s: Couldn't register DT provider\n", clk_name); goto free_clk; } if (!data->num_rst) return; reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); if (!reset_data) goto free_of_clk; reset_data->reg = reg; reset_data->offset = data->offset_rst; reset_data->lock = &sun4i_a10_display_lock; reset_data->rcdev.nr_resets = data->num_rst; reset_data->rcdev.ops = &sun4i_a10_display_reset_ops; reset_data->rcdev.of_node = node; if (data->num_rst == 1) { reset_data->rcdev.of_reset_n_cells = 0; reset_data->rcdev.of_xlate = &sun4i_a10_display_reset_xlate; } else { reset_data->rcdev.of_reset_n_cells = 1; } if (reset_controller_register(&reset_data->rcdev)) { pr_err("%s: Couldn't register the reset controller\n", clk_name); goto free_reset; } return; free_reset: kfree(reset_data); free_of_clk: of_clk_del_provider(node); free_clk: clk_unregister_composite(clk); free_div: kfree(div); free_gate: kfree(gate); free_mux: kfree(mux); unmap: iounmap(reg); of_address_to_resource(node, 0, &res); release_mem_region(res.start, resource_size(&res)); }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard615100.00%2100.00%
Total615100.00%2100.00%

static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst = { .num_rst = 2, .parents = 4, .offset_en = 31, .offset_rst = 29, .offset_mux = 24, .width_mux = 2, .flags = CLK_SET_RATE_PARENT, };
static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node) { sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data); }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard20100.00%1100.00%
Total20100.00%1100.00%

CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk", sun4i_a10_tcon_ch0_setup); static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst = { .has_div = true, .num_rst = 1, .parents = 3, .offset_en = 31, .offset_rst = 30, .offset_mux = 24, .offset_div = 0, .width_mux = 2, .width_div = 4, };
static void __init sun4i_a10_display_setup(struct device_node *node) { sun4i_a10_display_init(node, &sun4i_a10_display_data); }

Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard20100.00%1100.00%
Total20100.00%1100.00%

CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk", sun4i_a10_display_setup);

Overall Contributors

PersonTokensPropCommitsCommitProp
maxime ripardmaxime ripard1128100.00%2100.00%
Total1128100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}