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