at v3.17-rc2 190 lines 4.3 kB view raw
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_data/syscon.h> 22#include <linux/platform_device.h> 23#include <linux/regmap.h> 24#include <linux/mfd/syscon.h> 25 26static struct platform_driver syscon_driver; 27 28struct syscon { 29 struct regmap *regmap; 30}; 31 32static int syscon_match_node(struct device *dev, void *data) 33{ 34 struct device_node *dn = data; 35 36 return (dev->of_node == dn) ? 1 : 0; 37} 38 39struct regmap *syscon_node_to_regmap(struct device_node *np) 40{ 41 struct syscon *syscon; 42 struct device *dev; 43 44 dev = driver_find_device(&syscon_driver.driver, NULL, np, 45 syscon_match_node); 46 if (!dev) 47 return ERR_PTR(-EPROBE_DEFER); 48 49 syscon = dev_get_drvdata(dev); 50 51 return syscon->regmap; 52} 53EXPORT_SYMBOL_GPL(syscon_node_to_regmap); 54 55struct regmap *syscon_regmap_lookup_by_compatible(const char *s) 56{ 57 struct device_node *syscon_np; 58 struct regmap *regmap; 59 60 syscon_np = of_find_compatible_node(NULL, NULL, s); 61 if (!syscon_np) 62 return ERR_PTR(-ENODEV); 63 64 regmap = syscon_node_to_regmap(syscon_np); 65 of_node_put(syscon_np); 66 67 return regmap; 68} 69EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); 70 71static int syscon_match_pdevname(struct device *dev, void *data) 72{ 73 return !strcmp(dev_name(dev), (const char *)data); 74} 75 76struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) 77{ 78 struct device *dev; 79 struct syscon *syscon; 80 81 dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, 82 syscon_match_pdevname); 83 if (!dev) 84 return ERR_PTR(-EPROBE_DEFER); 85 86 syscon = dev_get_drvdata(dev); 87 88 return syscon->regmap; 89} 90EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); 91 92struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, 93 const char *property) 94{ 95 struct device_node *syscon_np; 96 struct regmap *regmap; 97 98 if (property) 99 syscon_np = of_parse_phandle(np, property, 0); 100 else 101 syscon_np = np; 102 103 if (!syscon_np) 104 return ERR_PTR(-ENODEV); 105 106 regmap = syscon_node_to_regmap(syscon_np); 107 of_node_put(syscon_np); 108 109 return regmap; 110} 111EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); 112 113static const struct of_device_id of_syscon_match[] = { 114 { .compatible = "syscon", }, 115 { }, 116}; 117 118static struct regmap_config syscon_regmap_config = { 119 .reg_bits = 32, 120 .val_bits = 32, 121 .reg_stride = 4, 122}; 123 124static int syscon_probe(struct platform_device *pdev) 125{ 126 struct device *dev = &pdev->dev; 127 struct syscon_platform_data *pdata = dev_get_platdata(dev); 128 struct syscon *syscon; 129 struct resource *res; 130 void __iomem *base; 131 132 syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); 133 if (!syscon) 134 return -ENOMEM; 135 136 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 137 if (!res) 138 return -ENOENT; 139 140 base = devm_ioremap(dev, res->start, resource_size(res)); 141 if (!base) 142 return -ENOMEM; 143 144 syscon_regmap_config.max_register = res->end - res->start - 3; 145 if (pdata) 146 syscon_regmap_config.name = pdata->label; 147 syscon->regmap = devm_regmap_init_mmio(dev, base, 148 &syscon_regmap_config); 149 if (IS_ERR(syscon->regmap)) { 150 dev_err(dev, "regmap init failed\n"); 151 return PTR_ERR(syscon->regmap); 152 } 153 154 platform_set_drvdata(pdev, syscon); 155 156 dev_dbg(dev, "regmap %pR registered\n", res); 157 158 return 0; 159} 160 161static const struct platform_device_id syscon_ids[] = { 162 { "syscon", }, 163 { } 164}; 165 166static struct platform_driver syscon_driver = { 167 .driver = { 168 .name = "syscon", 169 .owner = THIS_MODULE, 170 .of_match_table = of_syscon_match, 171 }, 172 .probe = syscon_probe, 173 .id_table = syscon_ids, 174}; 175 176static int __init syscon_init(void) 177{ 178 return platform_driver_register(&syscon_driver); 179} 180postcore_initcall(syscon_init); 181 182static void __exit syscon_exit(void) 183{ 184 platform_driver_unregister(&syscon_driver); 185} 186module_exit(syscon_exit); 187 188MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>"); 189MODULE_DESCRIPTION("System Control driver"); 190MODULE_LICENSE("GPL v2");