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