brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 85c395d Raw
139 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Clock driver for the ARM Integrator/IM-PD1 board4 * Copyright (C) 2012-2013 Linus Walleij5 */6#include <linux/clk-provider.h>7#include <linux/clkdev.h>8#include <linux/err.h>9#include <linux/io.h>10#include <linux/platform_device.h>11#include <linux/module.h>12#include <linux/mfd/syscon.h>13#include <linux/regmap.h>14 15#include "icst.h"16#include "clk-icst.h"17 18#define IMPD1_OSC1	0x0019#define IMPD1_OSC2	0x0420#define IMPD1_LOCK	0x0821 22/*23 * There are two VCO's on the IM-PD124 */25 26static const struct icst_params impd1_vco1_params = {27	.ref		= 24000000,	/* 24 MHz */28	.vco_max	= ICST525_VCO_MAX_3V,29	.vco_min	= ICST525_VCO_MIN,30	.vd_min		= 12,31	.vd_max		= 519,32	.rd_min		= 3,33	.rd_max		= 120,34	.s2div		= icst525_s2div,35	.idx2s		= icst525_idx2s,36};37 38static const struct clk_icst_desc impd1_icst1_desc = {39	.params = &impd1_vco1_params,40	.vco_offset = IMPD1_OSC1,41	.lock_offset = IMPD1_LOCK,42};43 44static const struct icst_params impd1_vco2_params = {45	.ref		= 24000000,	/* 24 MHz */46	.vco_max	= ICST525_VCO_MAX_3V,47	.vco_min	= ICST525_VCO_MIN,48	.vd_min		= 12,49	.vd_max		= 519,50	.rd_min		= 3,51	.rd_max		= 120,52	.s2div		= icst525_s2div,53	.idx2s		= icst525_idx2s,54};55 56static const struct clk_icst_desc impd1_icst2_desc = {57	.params = &impd1_vco2_params,58	.vco_offset = IMPD1_OSC2,59	.lock_offset = IMPD1_LOCK,60};61 62static int integrator_impd1_clk_spawn(struct device *dev,63				      struct device_node *parent,64				      struct device_node *np)65{66	struct regmap *map;67	struct clk *clk = ERR_PTR(-EINVAL);68	const char *name = np->name;69	const char *parent_name;70	const struct clk_icst_desc *desc;71	int ret;72 73	map = syscon_node_to_regmap(parent);74	if (IS_ERR(map)) {75		pr_err("no regmap for syscon IM-PD1 ICST clock parent\n");76		return PTR_ERR(map);77	}78 79	if (of_device_is_compatible(np, "arm,impd1-vco1")) {80		desc = &impd1_icst1_desc;81	} else if (of_device_is_compatible(np, "arm,impd1-vco2")) {82		desc = &impd1_icst2_desc;83	} else {84		dev_err(dev, "not a clock node %s\n", name);85		return -ENODEV;86	}87 88	of_property_read_string(np, "clock-output-names", &name);89	parent_name = of_clk_get_parent_name(np, 0);90	clk = icst_clk_setup(NULL, desc, name, parent_name, map,91			     ICST_INTEGRATOR_IM_PD1);92	if (!IS_ERR(clk)) {93		of_clk_add_provider(np, of_clk_src_simple_get, clk);94		ret = 0;95	} else {96		dev_err(dev, "error setting up IM-PD1 ICST clock\n");97		ret = PTR_ERR(clk);98	}99 100	return ret;101}102 103static int integrator_impd1_clk_probe(struct platform_device *pdev)104{105	struct device *dev = &pdev->dev;106	struct device_node *np = dev->of_node;107	struct device_node *child;108	int ret = 0;109 110	for_each_available_child_of_node(np, child) {111		ret = integrator_impd1_clk_spawn(dev, np, child);112		if (ret) {113			of_node_put(child);114			break;115		}116	}117 118	return ret;119}120 121static const struct of_device_id impd1_syscon_match[] = {122	{ .compatible = "arm,im-pd1-syscon", },123	{}124};125MODULE_DEVICE_TABLE(of, impd1_syscon_match);126 127static struct platform_driver impd1_clk_driver = {128	.driver = {129		.name = "impd1-clk",130		.of_match_table = impd1_syscon_match,131	},132	.probe  = integrator_impd1_clk_probe,133};134builtin_platform_driver(impd1_clk_driver);135 136MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");137MODULE_DESCRIPTION("Arm IM-PD1 module clock driver");138MODULE_LICENSE("GPL v2");139