1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Marvell Armada 37xx SoC xtal clocks |
4 | * |
5 | * Copyright (C) 2016 Marvell |
6 | * |
7 | * Gregory CLEMENT <gregory.clement@free-electrons.com> |
8 | * |
9 | */ |
10 | |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/mfd/syscon.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/regmap.h> |
15 | |
16 | #define NB_GPIO1_LATCH 0x8 |
17 | #define XTAL_MODE BIT(9) |
18 | |
19 | static int armada_3700_xtal_clock_probe(struct platform_device *pdev) |
20 | { |
21 | struct device_node *np = pdev->dev.of_node; |
22 | const char *xtal_name = "xtal" ; |
23 | struct device_node *parent; |
24 | struct regmap *regmap; |
25 | struct clk_hw *xtal_hw; |
26 | unsigned int rate; |
27 | u32 reg; |
28 | int ret; |
29 | |
30 | xtal_hw = devm_kzalloc(dev: &pdev->dev, size: sizeof(*xtal_hw), GFP_KERNEL); |
31 | if (!xtal_hw) |
32 | return -ENOMEM; |
33 | |
34 | platform_set_drvdata(pdev, data: xtal_hw); |
35 | |
36 | parent = np->parent; |
37 | if (!parent) { |
38 | dev_err(&pdev->dev, "no parent\n" ); |
39 | return -ENODEV; |
40 | } |
41 | |
42 | regmap = syscon_node_to_regmap(np: parent); |
43 | if (IS_ERR(ptr: regmap)) { |
44 | dev_err(&pdev->dev, "cannot get regmap\n" ); |
45 | return PTR_ERR(ptr: regmap); |
46 | } |
47 | |
48 | ret = regmap_read(map: regmap, NB_GPIO1_LATCH, val: ®); |
49 | if (ret) { |
50 | dev_err(&pdev->dev, "cannot read from regmap\n" ); |
51 | return ret; |
52 | } |
53 | |
54 | if (reg & XTAL_MODE) |
55 | rate = 40000000; |
56 | else |
57 | rate = 25000000; |
58 | |
59 | of_property_read_string_index(np, propname: "clock-output-names" , index: 0, output: &xtal_name); |
60 | xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate); |
61 | if (IS_ERR(ptr: xtal_hw)) |
62 | return PTR_ERR(ptr: xtal_hw); |
63 | ret = of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: xtal_hw); |
64 | |
65 | return ret; |
66 | } |
67 | |
68 | static void armada_3700_xtal_clock_remove(struct platform_device *pdev) |
69 | { |
70 | of_clk_del_provider(np: pdev->dev.of_node); |
71 | } |
72 | |
73 | static const struct of_device_id armada_3700_xtal_clock_of_match[] = { |
74 | { .compatible = "marvell,armada-3700-xtal-clock" , }, |
75 | { } |
76 | }; |
77 | |
78 | static struct platform_driver armada_3700_xtal_clock_driver = { |
79 | .probe = armada_3700_xtal_clock_probe, |
80 | .remove_new = armada_3700_xtal_clock_remove, |
81 | .driver = { |
82 | .name = "marvell-armada-3700-xtal-clock" , |
83 | .of_match_table = armada_3700_xtal_clock_of_match, |
84 | }, |
85 | }; |
86 | |
87 | builtin_platform_driver(armada_3700_xtal_clock_driver); |
88 | |