diff options
Diffstat (limited to 'drivers/clk/clk-fixed-mmio.c')
| -rw-r--r-- | drivers/clk/clk-fixed-mmio.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/clk/clk-fixed-mmio.c b/drivers/clk/clk-fixed-mmio.c new file mode 100644 index 000000000000..d1a97d971183 --- /dev/null +++ b/drivers/clk/clk-fixed-mmio.c | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Memory Mapped IO Fixed clock driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2018 Cadence Design Systems, Inc. | ||
| 7 | * | ||
| 8 | * Authors: | ||
| 9 | * Jan Kotas <jank@cadence.com> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/clk-provider.h> | ||
| 13 | #include <linux/of_address.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | |||
| 17 | static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node) | ||
| 18 | { | ||
| 19 | struct clk_hw *clk; | ||
| 20 | const char *clk_name = node->name; | ||
| 21 | void __iomem *base; | ||
| 22 | u32 freq; | ||
| 23 | int ret; | ||
| 24 | |||
| 25 | base = of_iomap(node, 0); | ||
| 26 | if (!base) { | ||
| 27 | pr_err("%pOFn: failed to map address\n", node); | ||
| 28 | return ERR_PTR(-EIO); | ||
| 29 | } | ||
| 30 | |||
| 31 | freq = readl(base); | ||
| 32 | iounmap(base); | ||
| 33 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
| 34 | |||
| 35 | clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq); | ||
| 36 | if (IS_ERR(clk)) { | ||
| 37 | pr_err("%pOFn: failed to register fixed rate clock\n", node); | ||
| 38 | return clk; | ||
| 39 | } | ||
| 40 | |||
| 41 | ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk); | ||
| 42 | if (ret) { | ||
| 43 | pr_err("%pOFn: failed to add clock provider\n", node); | ||
| 44 | clk_hw_unregister(clk); | ||
| 45 | clk = ERR_PTR(ret); | ||
| 46 | } | ||
| 47 | |||
| 48 | return clk; | ||
| 49 | } | ||
| 50 | |||
| 51 | static void __init of_fixed_mmio_clk_setup(struct device_node *node) | ||
| 52 | { | ||
| 53 | fixed_mmio_clk_setup(node); | ||
| 54 | } | ||
| 55 | CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup); | ||
| 56 | |||
| 57 | /** | ||
| 58 | * This is not executed when of_fixed_mmio_clk_setup succeeded. | ||
| 59 | */ | ||
| 60 | static int of_fixed_mmio_clk_probe(struct platform_device *pdev) | ||
| 61 | { | ||
| 62 | struct clk_hw *clk; | ||
| 63 | |||
| 64 | clk = fixed_mmio_clk_setup(pdev->dev.of_node); | ||
| 65 | if (IS_ERR(clk)) | ||
| 66 | return PTR_ERR(clk); | ||
| 67 | |||
| 68 | platform_set_drvdata(pdev, clk); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int of_fixed_mmio_clk_remove(struct platform_device *pdev) | ||
| 74 | { | ||
| 75 | struct clk_hw *clk = platform_get_drvdata(pdev); | ||
| 76 | |||
| 77 | of_clk_del_provider(pdev->dev.of_node); | ||
| 78 | clk_hw_unregister_fixed_rate(clk); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static const struct of_device_id of_fixed_mmio_clk_ids[] = { | ||
| 84 | { .compatible = "fixed-mmio-clock" }, | ||
| 85 | { } | ||
| 86 | }; | ||
| 87 | MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids); | ||
| 88 | |||
| 89 | static struct platform_driver of_fixed_mmio_clk_driver = { | ||
| 90 | .driver = { | ||
| 91 | .name = "of_fixed_mmio_clk", | ||
| 92 | .of_match_table = of_fixed_mmio_clk_ids, | ||
| 93 | }, | ||
| 94 | .probe = of_fixed_mmio_clk_probe, | ||
| 95 | .remove = of_fixed_mmio_clk_remove, | ||
| 96 | }; | ||
| 97 | module_platform_driver(of_fixed_mmio_clk_driver); | ||
| 98 | |||
| 99 | MODULE_AUTHOR("Jan Kotas <jank@cadence.com>"); | ||
| 100 | MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver"); | ||
| 101 | MODULE_LICENSE("GPL v2"); | ||
