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(&pdev->dev, sizeof(*xtal_hw), GFP_KERNEL); 31 if (!xtal_hw) 32 return -ENOMEM; 33 34 platform_set_drvdata(pdev, 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(parent); 43 if (IS_ERR(regmap)) { 44 dev_err(&pdev->dev, "cannot get regmap\n"); 45 return PTR_ERR(regmap); 46 } 47 48 ret = regmap_read(regmap, NB_GPIO1_LATCH, ®); 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, "clock-output-names", 0, &xtal_name); 60 xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate); 61 if (IS_ERR(xtal_hw)) 62 return PTR_ERR(xtal_hw); 63 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, xtal_hw); 64 65 return ret; 66 } 67 68 static int armada_3700_xtal_clock_remove(struct platform_device *pdev) 69 { 70 of_clk_del_provider(pdev->dev.of_node); 71 72 return 0; 73 } 74 75 static const struct of_device_id armada_3700_xtal_clock_of_match[] = { 76 { .compatible = "marvell,armada-3700-xtal-clock", }, 77 { } 78 }; 79 80 static struct platform_driver armada_3700_xtal_clock_driver = { 81 .probe = armada_3700_xtal_clock_probe, 82 .remove = armada_3700_xtal_clock_remove, 83 .driver = { 84 .name = "marvell-armada-3700-xtal-clock", 85 .of_match_table = armada_3700_xtal_clock_of_match, 86 }, 87 }; 88 89 builtin_platform_driver(armada_3700_xtal_clock_driver); 90