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