forked from Minki/linux
45330bb434
If we pass syscon device node itself as first parameter to this function there is no need to parse and find syscon device node. So by allowing "property" parameter as NULL allow syscon_regmap_lookup_by_phandle to consider passed argument "np" itself as a syscon device node "syscon_np". This will help us in avoiding addition of "syscon" property in a device node which points back to same device node in device tree. Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
187 lines
4.1 KiB
C
187 lines
4.1 KiB
C
/*
|
|
* System Control Driver
|
|
*
|
|
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
|
* Copyright (C) 2012 Linaro Ltd.
|
|
*
|
|
* Author: Dong Aisheng <dong.aisheng@linaro.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/mfd/syscon.h>
|
|
|
|
static struct platform_driver syscon_driver;
|
|
|
|
struct syscon {
|
|
struct regmap *regmap;
|
|
};
|
|
|
|
static int syscon_match_node(struct device *dev, void *data)
|
|
{
|
|
struct device_node *dn = data;
|
|
|
|
return (dev->of_node == dn) ? 1 : 0;
|
|
}
|
|
|
|
struct regmap *syscon_node_to_regmap(struct device_node *np)
|
|
{
|
|
struct syscon *syscon;
|
|
struct device *dev;
|
|
|
|
dev = driver_find_device(&syscon_driver.driver, NULL, np,
|
|
syscon_match_node);
|
|
if (!dev)
|
|
return ERR_PTR(-EPROBE_DEFER);
|
|
|
|
syscon = dev_get_drvdata(dev);
|
|
|
|
return syscon->regmap;
|
|
}
|
|
EXPORT_SYMBOL_GPL(syscon_node_to_regmap);
|
|
|
|
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
|
|
{
|
|
struct device_node *syscon_np;
|
|
struct regmap *regmap;
|
|
|
|
syscon_np = of_find_compatible_node(NULL, NULL, s);
|
|
if (!syscon_np)
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
regmap = syscon_node_to_regmap(syscon_np);
|
|
of_node_put(syscon_np);
|
|
|
|
return regmap;
|
|
}
|
|
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
|
|
|
|
static int syscon_match_pdevname(struct device *dev, void *data)
|
|
{
|
|
return !strcmp(dev_name(dev), (const char *)data);
|
|
}
|
|
|
|
struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
|
|
{
|
|
struct device *dev;
|
|
struct syscon *syscon;
|
|
|
|
dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s,
|
|
syscon_match_pdevname);
|
|
if (!dev)
|
|
return ERR_PTR(-EPROBE_DEFER);
|
|
|
|
syscon = dev_get_drvdata(dev);
|
|
|
|
return syscon->regmap;
|
|
}
|
|
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);
|
|
|
|
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
|
|
const char *property)
|
|
{
|
|
struct device_node *syscon_np;
|
|
struct regmap *regmap;
|
|
|
|
if (property)
|
|
syscon_np = of_parse_phandle(np, property, 0);
|
|
else
|
|
syscon_np = np;
|
|
|
|
if (!syscon_np)
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
regmap = syscon_node_to_regmap(syscon_np);
|
|
of_node_put(syscon_np);
|
|
|
|
return regmap;
|
|
}
|
|
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
|
|
|
|
static const struct of_device_id of_syscon_match[] = {
|
|
{ .compatible = "syscon", },
|
|
{ },
|
|
};
|
|
|
|
static struct regmap_config syscon_regmap_config = {
|
|
.reg_bits = 32,
|
|
.val_bits = 32,
|
|
.reg_stride = 4,
|
|
};
|
|
|
|
static int syscon_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct syscon *syscon;
|
|
struct resource *res;
|
|
void __iomem *base;
|
|
|
|
syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
|
|
if (!syscon)
|
|
return -ENOMEM;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!res)
|
|
return -ENOENT;
|
|
|
|
base = devm_ioremap(dev, res->start, resource_size(res));
|
|
if (!base)
|
|
return -ENOMEM;
|
|
|
|
syscon_regmap_config.max_register = res->end - res->start - 3;
|
|
syscon->regmap = devm_regmap_init_mmio(dev, base,
|
|
&syscon_regmap_config);
|
|
if (IS_ERR(syscon->regmap)) {
|
|
dev_err(dev, "regmap init failed\n");
|
|
return PTR_ERR(syscon->regmap);
|
|
}
|
|
|
|
platform_set_drvdata(pdev, syscon);
|
|
|
|
dev_dbg(dev, "regmap %pR registered\n", res);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct platform_device_id syscon_ids[] = {
|
|
{ "syscon", },
|
|
{ }
|
|
};
|
|
|
|
static struct platform_driver syscon_driver = {
|
|
.driver = {
|
|
.name = "syscon",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = of_syscon_match,
|
|
},
|
|
.probe = syscon_probe,
|
|
.id_table = syscon_ids,
|
|
};
|
|
|
|
static int __init syscon_init(void)
|
|
{
|
|
return platform_driver_register(&syscon_driver);
|
|
}
|
|
postcore_initcall(syscon_init);
|
|
|
|
static void __exit syscon_exit(void)
|
|
{
|
|
platform_driver_unregister(&syscon_driver);
|
|
}
|
|
module_exit(syscon_exit);
|
|
|
|
MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
|
|
MODULE_DESCRIPTION("System Control driver");
|
|
MODULE_LICENSE("GPL v2");
|