150cc4cafSJan Kotas // SPDX-License-Identifier: GPL-2.0 250cc4cafSJan Kotas 350cc4cafSJan Kotas /* 450cc4cafSJan Kotas * Memory Mapped IO Fixed clock driver 550cc4cafSJan Kotas * 650cc4cafSJan Kotas * Copyright (C) 2018 Cadence Design Systems, Inc. 750cc4cafSJan Kotas * 850cc4cafSJan Kotas * Authors: 950cc4cafSJan Kotas * Jan Kotas <jank@cadence.com> 1050cc4cafSJan Kotas */ 1150cc4cafSJan Kotas 1250cc4cafSJan Kotas #include <linux/clk-provider.h> 1350cc4cafSJan Kotas #include <linux/of_address.h> 1450cc4cafSJan Kotas #include <linux/module.h> 1550cc4cafSJan Kotas #include <linux/platform_device.h> 1650cc4cafSJan Kotas 1750cc4cafSJan Kotas static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node) 1850cc4cafSJan Kotas { 1950cc4cafSJan Kotas struct clk_hw *clk; 2050cc4cafSJan Kotas const char *clk_name = node->name; 2150cc4cafSJan Kotas void __iomem *base; 2250cc4cafSJan Kotas u32 freq; 2350cc4cafSJan Kotas int ret; 2450cc4cafSJan Kotas 2550cc4cafSJan Kotas base = of_iomap(node, 0); 2650cc4cafSJan Kotas if (!base) { 2750cc4cafSJan Kotas pr_err("%pOFn: failed to map address\n", node); 2850cc4cafSJan Kotas return ERR_PTR(-EIO); 2950cc4cafSJan Kotas } 3050cc4cafSJan Kotas 3150cc4cafSJan Kotas freq = readl(base); 3250cc4cafSJan Kotas iounmap(base); 3350cc4cafSJan Kotas of_property_read_string(node, "clock-output-names", &clk_name); 3450cc4cafSJan Kotas 3550cc4cafSJan Kotas clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq); 3650cc4cafSJan Kotas if (IS_ERR(clk)) { 3750cc4cafSJan Kotas pr_err("%pOFn: failed to register fixed rate clock\n", node); 3850cc4cafSJan Kotas return clk; 3950cc4cafSJan Kotas } 4050cc4cafSJan Kotas 4150cc4cafSJan Kotas ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk); 4250cc4cafSJan Kotas if (ret) { 4350cc4cafSJan Kotas pr_err("%pOFn: failed to add clock provider\n", node); 4450cc4cafSJan Kotas clk_hw_unregister(clk); 4550cc4cafSJan Kotas clk = ERR_PTR(ret); 4650cc4cafSJan Kotas } 4750cc4cafSJan Kotas 4850cc4cafSJan Kotas return clk; 4950cc4cafSJan Kotas } 5050cc4cafSJan Kotas 5150cc4cafSJan Kotas static void __init of_fixed_mmio_clk_setup(struct device_node *node) 5250cc4cafSJan Kotas { 5350cc4cafSJan Kotas fixed_mmio_clk_setup(node); 5450cc4cafSJan Kotas } 5550cc4cafSJan Kotas CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup); 5650cc4cafSJan Kotas 5750cc4cafSJan Kotas /** 5850cc4cafSJan Kotas * This is not executed when of_fixed_mmio_clk_setup succeeded. 5950cc4cafSJan Kotas */ 6050cc4cafSJan Kotas static int of_fixed_mmio_clk_probe(struct platform_device *pdev) 6150cc4cafSJan Kotas { 6250cc4cafSJan Kotas struct clk_hw *clk; 6350cc4cafSJan Kotas 6450cc4cafSJan Kotas clk = fixed_mmio_clk_setup(pdev->dev.of_node); 6550cc4cafSJan Kotas if (IS_ERR(clk)) 6650cc4cafSJan Kotas return PTR_ERR(clk); 6750cc4cafSJan Kotas 6850cc4cafSJan Kotas platform_set_drvdata(pdev, clk); 6950cc4cafSJan Kotas 7050cc4cafSJan Kotas return 0; 7150cc4cafSJan Kotas } 7250cc4cafSJan Kotas 7350cc4cafSJan Kotas static int of_fixed_mmio_clk_remove(struct platform_device *pdev) 7450cc4cafSJan Kotas { 7550cc4cafSJan Kotas struct clk_hw *clk = platform_get_drvdata(pdev); 7650cc4cafSJan Kotas 7750cc4cafSJan Kotas of_clk_del_provider(pdev->dev.of_node); 7850cc4cafSJan Kotas clk_hw_unregister_fixed_rate(clk); 7950cc4cafSJan Kotas 8050cc4cafSJan Kotas return 0; 8150cc4cafSJan Kotas } 8250cc4cafSJan Kotas 8350cc4cafSJan Kotas static const struct of_device_id of_fixed_mmio_clk_ids[] = { 8450cc4cafSJan Kotas { .compatible = "fixed-mmio-clock" }, 8550cc4cafSJan Kotas { } 8650cc4cafSJan Kotas }; 8750cc4cafSJan Kotas MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids); 8850cc4cafSJan Kotas 8950cc4cafSJan Kotas static struct platform_driver of_fixed_mmio_clk_driver = { 9050cc4cafSJan Kotas .driver = { 9150cc4cafSJan Kotas .name = "of_fixed_mmio_clk", 9250cc4cafSJan Kotas .of_match_table = of_fixed_mmio_clk_ids, 9350cc4cafSJan Kotas }, 9450cc4cafSJan Kotas .probe = of_fixed_mmio_clk_probe, 9550cc4cafSJan Kotas .remove = of_fixed_mmio_clk_remove, 9650cc4cafSJan Kotas }; 9750cc4cafSJan Kotas module_platform_driver(of_fixed_mmio_clk_driver); 9850cc4cafSJan Kotas 9950cc4cafSJan Kotas MODULE_AUTHOR("Jan Kotas <jank@cadence.com>"); 10050cc4cafSJan Kotas MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver"); 10150cc4cafSJan Kotas MODULE_LICENSE("GPL v2"); 102