1 /* 2 * System Control Driver 3 * 4 * Copyright (C) 2012 Freescale Semiconductor, Inc. 5 * Copyright (C) 2012 Linaro Ltd. 6 * 7 * Author: Dong Aisheng <dong.aisheng@linaro.org> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 */ 14 15 #include <linux/err.h> 16 #include <linux/io.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/of_address.h> 20 #include <linux/of_platform.h> 21 #include <linux/platform_device.h> 22 #include <linux/regmap.h> 23 #include <linux/mfd/syscon.h> 24 25 static struct platform_driver syscon_driver; 26 27 struct syscon { 28 struct regmap *regmap; 29 }; 30 31 static int syscon_match_node(struct device *dev, void *data) 32 { 33 struct device_node *dn = data; 34 35 return (dev->of_node == dn) ? 1 : 0; 36 } 37 38 struct regmap *syscon_node_to_regmap(struct device_node *np) 39 { 40 struct syscon *syscon; 41 struct device *dev; 42 43 dev = driver_find_device(&syscon_driver.driver, NULL, np, 44 syscon_match_node); 45 if (!dev) 46 return ERR_PTR(-EPROBE_DEFER); 47 48 syscon = dev_get_drvdata(dev); 49 50 return syscon->regmap; 51 } 52 EXPORT_SYMBOL_GPL(syscon_node_to_regmap); 53 54 struct regmap *syscon_regmap_lookup_by_compatible(const char *s) 55 { 56 struct device_node *syscon_np; 57 struct regmap *regmap; 58 59 syscon_np = of_find_compatible_node(NULL, NULL, s); 60 if (!syscon_np) 61 return ERR_PTR(-ENODEV); 62 63 regmap = syscon_node_to_regmap(syscon_np); 64 of_node_put(syscon_np); 65 66 return regmap; 67 } 68 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); 69 70 static int syscon_match_pdevname(struct device *dev, void *data) 71 { 72 return !strcmp(dev_name(dev), (const char *)data); 73 } 74 75 struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) 76 { 77 struct device *dev; 78 struct syscon *syscon; 79 80 dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, 81 syscon_match_pdevname); 82 if (!dev) 83 return ERR_PTR(-EPROBE_DEFER); 84 85 syscon = dev_get_drvdata(dev); 86 87 return syscon->regmap; 88 } 89 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); 90 91 struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, 92 const char *property) 93 { 94 struct device_node *syscon_np; 95 struct regmap *regmap; 96 97 syscon_np = of_parse_phandle(np, property, 0); 98 if (!syscon_np) 99 return ERR_PTR(-ENODEV); 100 101 regmap = syscon_node_to_regmap(syscon_np); 102 of_node_put(syscon_np); 103 104 return regmap; 105 } 106 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); 107 108 static const struct of_device_id of_syscon_match[] = { 109 { .compatible = "syscon", }, 110 { }, 111 }; 112 113 static struct regmap_config syscon_regmap_config = { 114 .reg_bits = 32, 115 .val_bits = 32, 116 .reg_stride = 4, 117 }; 118 119 static int syscon_probe(struct platform_device *pdev) 120 { 121 struct device *dev = &pdev->dev; 122 struct syscon *syscon; 123 struct resource *res; 124 void __iomem *base; 125 126 syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); 127 if (!syscon) 128 return -ENOMEM; 129 130 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 131 if (!res) 132 return -ENOENT; 133 134 base = devm_ioremap(dev, res->start, resource_size(res)); 135 if (!base) 136 return -ENOMEM; 137 138 syscon_regmap_config.max_register = res->end - res->start - 3; 139 syscon->regmap = devm_regmap_init_mmio(dev, base, 140 &syscon_regmap_config); 141 if (IS_ERR(syscon->regmap)) { 142 dev_err(dev, "regmap init failed\n"); 143 return PTR_ERR(syscon->regmap); 144 } 145 146 platform_set_drvdata(pdev, syscon); 147 148 dev_dbg(dev, "regmap %pR registered\n", res); 149 150 return 0; 151 } 152 153 static const struct platform_device_id syscon_ids[] = { 154 { "syscon", }, 155 { } 156 }; 157 158 static struct platform_driver syscon_driver = { 159 .driver = { 160 .name = "syscon", 161 .owner = THIS_MODULE, 162 .of_match_table = of_syscon_match, 163 }, 164 .probe = syscon_probe, 165 .id_table = syscon_ids, 166 }; 167 168 static int __init syscon_init(void) 169 { 170 return platform_driver_register(&syscon_driver); 171 } 172 postcore_initcall(syscon_init); 173 174 static void __exit syscon_exit(void) 175 { 176 platform_driver_unregister(&syscon_driver); 177 } 178 module_exit(syscon_exit); 179 180 MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>"); 181 MODULE_DESCRIPTION("System Control driver"); 182 MODULE_LICENSE("GPL v2"); 183