cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-sun6i-apb0-gates.c (2553B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Free Electrons
      4 *
      5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
      6 *
      7 * Allwinner A31 APB0 clock gates driver
      8 */
      9
     10#include <linux/clk-provider.h>
     11#include <linux/init.h>
     12#include <linux/of.h>
     13#include <linux/of_device.h>
     14#include <linux/platform_device.h>
     15
     16#define SUN6I_APB0_GATES_MAX_SIZE	32
     17
     18struct gates_data {
     19	DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE);
     20};
     21
     22static const struct gates_data sun6i_a31_apb0_gates __initconst = {
     23	.mask = {0x7F},
     24};
     25
     26static const struct gates_data sun8i_a23_apb0_gates __initconst = {
     27	.mask = {0x5D},
     28};
     29
     30static const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
     31	{ .compatible = "allwinner,sun6i-a31-apb0-gates-clk", .data = &sun6i_a31_apb0_gates },
     32	{ .compatible = "allwinner,sun8i-a23-apb0-gates-clk", .data = &sun8i_a23_apb0_gates },
     33	{ /* sentinel */ }
     34};
     35
     36static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
     37{
     38	struct device_node *np = pdev->dev.of_node;
     39	struct clk_onecell_data *clk_data;
     40	const struct gates_data *data;
     41	const char *clk_parent;
     42	const char *clk_name;
     43	void __iomem *reg;
     44	int ngates;
     45	int i;
     46	int j = 0;
     47
     48	if (!np)
     49		return -ENODEV;
     50
     51	data = of_device_get_match_data(&pdev->dev);
     52	if (!data)
     53		return -ENODEV;
     54
     55	reg = devm_platform_ioremap_resource(pdev, 0);
     56	if (IS_ERR(reg))
     57		return PTR_ERR(reg);
     58
     59	clk_parent = of_clk_get_parent_name(np, 0);
     60	if (!clk_parent)
     61		return -EINVAL;
     62
     63	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
     64				GFP_KERNEL);
     65	if (!clk_data)
     66		return -ENOMEM;
     67
     68	/* Worst-case size approximation and memory allocation */
     69	ngates = find_last_bit(data->mask, SUN6I_APB0_GATES_MAX_SIZE);
     70	clk_data->clks = devm_kcalloc(&pdev->dev, (ngates + 1),
     71				      sizeof(struct clk *), GFP_KERNEL);
     72	if (!clk_data->clks)
     73		return -ENOMEM;
     74
     75	for_each_set_bit(i, data->mask, SUN6I_APB0_GATES_MAX_SIZE) {
     76		of_property_read_string_index(np, "clock-output-names",
     77					      j, &clk_name);
     78
     79		clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
     80						      clk_parent, 0, reg, i,
     81						      0, NULL);
     82		WARN_ON(IS_ERR(clk_data->clks[i]));
     83
     84		j++;
     85	}
     86
     87	clk_data->clk_num = ngates + 1;
     88
     89	return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
     90}
     91
     92static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
     93	.driver = {
     94		.name = "sun6i-a31-apb0-gates-clk",
     95		.of_match_table = sun6i_a31_apb0_gates_clk_dt_ids,
     96	},
     97	.probe = sun6i_a31_apb0_gates_clk_probe,
     98};
     99builtin_platform_driver(sun6i_a31_apb0_gates_clk_driver);