Blame view

drivers/mfd/syscon.c 4.02 KB
87d687301   Dong Aisheng   mfd: Add syscon d...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * 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>
75177deee   Fabio Estevam   mfd: syscon: Fix ...
23
  #include <linux/mfd/syscon.h>
87d687301   Dong Aisheng   mfd: Add syscon d...
24
25
26
27
  
  static struct platform_driver syscon_driver;
  
  struct syscon {
87d687301   Dong Aisheng   mfd: Add syscon d...
28
29
  	struct regmap *regmap;
  };
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
30
  static int syscon_match_node(struct device *dev, void *data)
87d687301   Dong Aisheng   mfd: Add syscon d...
31
  {
87d687301   Dong Aisheng   mfd: Add syscon d...
32
  	struct device_node *dn = data;
ed21465a0   Alexander Shiyan   mfd: syscon: Remo...
33
  	return (dev->of_node == dn) ? 1 : 0;
87d687301   Dong Aisheng   mfd: Add syscon d...
34
35
36
37
38
39
40
41
  }
  
  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,
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
42
  				 syscon_match_node);
87d687301   Dong Aisheng   mfd: Add syscon d...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  	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);
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
67
68
  static int syscon_match_pdevname(struct device *dev, void *data)
  {
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  	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);
87d687301   Dong Aisheng   mfd: Add syscon d...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
  					const char *property)
  {
  	struct device_node *syscon_np;
  	struct regmap *regmap;
  
  	syscon_np = of_parse_phandle(np, property, 0);
  	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,
  };
f791be492   Bill Pemberton   mfd: remove use o...
114
  static int syscon_probe(struct platform_device *pdev)
87d687301   Dong Aisheng   mfd: Add syscon d...
115
116
  {
  	struct device *dev = &pdev->dev;
87d687301   Dong Aisheng   mfd: Add syscon d...
117
  	struct syscon *syscon;
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
118
  	struct resource *res;
f10111cc8   Alexander Shiyan   mfd: syscon: Remo...
119
  	void __iomem *base;
87d687301   Dong Aisheng   mfd: Add syscon d...
120

5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
121
  	syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
87d687301   Dong Aisheng   mfd: Add syscon d...
122
123
  	if (!syscon)
  		return -ENOMEM;
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
124
125
126
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -ENOENT;
87d687301   Dong Aisheng   mfd: Add syscon d...
127

f10111cc8   Alexander Shiyan   mfd: syscon: Remo...
128
129
  	base = devm_ioremap(dev, res->start, resource_size(res));
  	if (!base)
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
130
  		return -ENOMEM;
87d687301   Dong Aisheng   mfd: Add syscon d...
131

5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
132
  	syscon_regmap_config.max_register = res->end - res->start - 3;
f10111cc8   Alexander Shiyan   mfd: syscon: Remo...
133
  	syscon->regmap = devm_regmap_init_mmio(dev, base,
87d687301   Dong Aisheng   mfd: Add syscon d...
134
135
136
137
138
139
  					&syscon_regmap_config);
  	if (IS_ERR(syscon->regmap)) {
  		dev_err(dev, "regmap init failed
  ");
  		return PTR_ERR(syscon->regmap);
  	}
87d687301   Dong Aisheng   mfd: Add syscon d...
140
  	platform_set_drvdata(pdev, syscon);
38d8974e3   Alexander Shiyan   mfd: syscon: Move...
141
142
  	dev_dbg(dev, "regmap %pR registered
  ", res);
87d687301   Dong Aisheng   mfd: Add syscon d...
143
144
145
  
  	return 0;
  }
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
146
147
148
149
  static const struct platform_device_id syscon_ids[] = {
  	{ "syscon", },
  	{ }
  };
87d687301   Dong Aisheng   mfd: Add syscon d...
150
151
152
153
154
155
156
157
  
  static struct platform_driver syscon_driver = {
  	.driver = {
  		.name = "syscon",
  		.owner = THIS_MODULE,
  		.of_match_table = of_syscon_match,
  	},
  	.probe		= syscon_probe,
5ab3a89a7   Alexander Shiyan   mfd: syscon: Add ...
158
  	.id_table	= syscon_ids,
87d687301   Dong Aisheng   mfd: Add syscon d...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  };
  
  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");