blob: 6fdfe93cdc70434c5d61886f7183254bbfb83802 [file] [log] [blame]
Edward A. James7bd86372017-05-15 12:28:44 -05001From 8f10daa0cc99ce286b9a2f249f1fa0a245d4fc03 Mon Sep 17 00:00:00 2001
2From: "Edward A. James" <eajames@us.ibm.com>
3Date: Wed, 17 May 2017 09:46:19 -0500
4Subject: [PATCH] fsi: Match fsi slaves & engines to available device tree
5 nodes
6
7This change populates device tree nodes for scanned FSI slaves and
8engines. If the master populates ->of_node of the FSI master device,
9we'll look for matching slaves, and under those slaves we'll look for
10matching engines.
11
12This means that FSI drivers will have their ->of_node pointer populated
13if there's a corresponding DT node, which they can use for further
14device discover.
15
16Presence of device tree nodes is optional, and only required for
17fsi device drivers that need extra properties, or subordinate devices,
18to be enumerated.
19
20Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
21Signed-off-by: Edward A. James <eajames@us.ibm.com>
22---
23 drivers/fsi/fsi-core.c | 99 +++++++++++++++++++++++++++++++++++++++++++
24 drivers/fsi/fsi-master-gpio.c | 4 ++
25 drivers/fsi/fsi-master-hub.c | 4 ++
26 3 files changed, 107 insertions(+)
27
28diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
29index 7ca5b74..71e3af9 100644
30--- a/drivers/fsi/fsi-core.c
31+++ b/drivers/fsi/fsi-core.c
32@@ -17,6 +17,7 @@
33 #include <linux/fsi.h>
34 #include <linux/idr.h>
35 #include <linux/module.h>
36+#include <linux/of.h>
37 #include <linux/slab.h>
38
39 #include "fsi-master.h"
40@@ -125,6 +126,7 @@ static void fsi_device_release(struct device *_device)
41 {
42 struct fsi_device *device = to_fsi_dev(_device);
43
44+ of_node_put(device->dev.of_node);
45 kfree(device);
46 }
47
48@@ -337,6 +339,57 @@ extern void fsi_slave_release_range(struct fsi_slave *slave,
49 {
50 }
51
52+static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
53+ uint32_t addr, uint32_t size)
54+{
55+ unsigned int len, na, ns;
56+ const __be32 *prop;
57+ uint32_t psize;
58+
59+ na = of_n_addr_cells(np);
60+ ns = of_n_size_cells(np);
61+
62+ if (na != 1 || ns != 1)
63+ return false;
64+
65+ prop = of_get_property(np, "reg", &len);
66+ if (!prop || len != 8)
67+ return false;
68+
69+ if (of_read_number(prop, 1) != addr)
70+ return false;
71+
72+ psize = of_read_number(prop + 1, 1);
73+ if (psize != size) {
74+ dev_warn(dev,
75+ "node %s matches probed address, but not size (got 0x%x, expected 0x%x)",
76+ of_node_full_name(np), psize, size);
77+ }
78+
79+ return true;
80+}
81+
82+/* Find a matching node for the slave engine at @address, using @size bytes
83+ * of space. Returns NULL if not found, or a matching node with refcount
84+ * already incremented.
85+ */
86+static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
87+{
88+ struct device_node *parent, *np;
89+
90+ parent = dev_of_node(&dev->slave->dev);
91+ if (!parent)
92+ return NULL;
93+
94+ for_each_child_of_node(parent, np) {
95+ if (fsi_device_node_matches(&dev->dev, np,
96+ dev->addr, dev->size))
97+ return np;
98+ }
99+
100+ return NULL;
101+}
102+
103 static int fsi_slave_scan(struct fsi_slave *slave)
104 {
105 uint32_t engine_addr;
106@@ -405,6 +458,7 @@ static int fsi_slave_scan(struct fsi_slave *slave)
107 dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
108 slave->master->idx, slave->link,
109 slave->id, i - 2);
110+ dev->dev.of_node = fsi_device_find_of_node(dev);
111
112 rc = device_register(&dev->dev);
113 if (rc) {
114@@ -561,9 +615,53 @@ static void fsi_slave_release(struct device *dev)
115 {
116 struct fsi_slave *slave = to_fsi_slave(dev);
117
118+ of_node_put(dev->of_node);
119 kfree(slave);
120 }
121
122+static bool fsi_slave_node_matches(struct device_node *np,
123+ int link, uint8_t id)
124+{
125+ unsigned int len, na, ns;
126+ const __be32 *prop;
127+
128+ na = of_n_addr_cells(np);
129+ ns = of_n_size_cells(np);
130+
131+ /* Ensure we have the correct format for addresses and sizes in
132+ * reg properties
133+ */
134+ if (na != 2 || ns != 0)
135+ return false;
136+
137+ prop = of_get_property(np, "reg", &len);
138+ if (!prop || len != 8)
139+ return false;
140+
141+ return (of_read_number(prop, 1) == link) &&
142+ (of_read_number(prop + 1, 1) == id);
143+}
144+
145+/* Find a matching node for the slave at (link, id). Returns NULL if none
146+ * found, or a matching node with refcount already incremented.
147+ */
148+static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
149+ int link, uint8_t id)
150+{
151+ struct device_node *parent, *np;
152+
153+ parent = dev_of_node(&master->dev);
154+ if (!parent)
155+ return NULL;
156+
157+ for_each_child_of_node(parent, np) {
158+ if (fsi_slave_node_matches(np, link, id))
159+ return np;
160+ }
161+
162+ return NULL;
163+}
164+
165 static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
166 {
167 uint32_t chip_id, llmode;
168@@ -626,6 +724,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
169
170 slave->master = master;
171 slave->dev.parent = &master->dev;
172+ slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
173 slave->dev.release = fsi_slave_release;
174 slave->link = link;
175 slave->id = id;
176diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
177index ef209ef..2a6a812 100644
178--- a/drivers/fsi/fsi-master-gpio.c
179+++ b/drivers/fsi/fsi-master-gpio.c
180@@ -5,6 +5,7 @@
181 #include <linux/platform_device.h>
182 #include <linux/gpio/consumer.h>
183 #include <linux/module.h>
184+#include <linux/of.h>
185 #include <linux/delay.h>
186 #include <linux/fsi.h>
187 #include <linux/device.h>
188@@ -529,6 +530,7 @@ static int fsi_master_gpio_probe(struct platform_device *pdev)
189
190 master->dev = &pdev->dev;
191 master->master.dev.parent = master->dev;
192+ master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
193 master->master.dev.release = fsi_master_gpio_release;
194
195 gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
196@@ -598,6 +600,8 @@ static int fsi_master_gpio_remove(struct platform_device *pdev)
197 devm_gpiod_put(&pdev->dev, master->gpio_mux);
198 fsi_master_unregister(&master->master);
199
200+ of_node_put(master->master.dev.of_node);
201+
202 return 0;
203 }
204
205diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
206index 133b9bf..3223a67 100644
207--- a/drivers/fsi/fsi-master-hub.c
208+++ b/drivers/fsi/fsi-master-hub.c
209@@ -16,6 +16,7 @@
210 #include <linux/delay.h>
211 #include <linux/fsi.h>
212 #include <linux/module.h>
213+#include <linux/of.h>
214 #include <linux/slab.h>
215
216 #include "fsi-master.h"
217@@ -274,6 +275,7 @@ static int hub_master_probe(struct device *dev)
218
219 hub->master.dev.parent = dev;
220 hub->master.dev.release = hub_master_release;
221+ hub->master.dev.of_node = of_node_get(dev_of_node(dev));
222
223 hub->master.n_links = links;
224 hub->master.read = hub_master_read;
225@@ -302,6 +304,8 @@ static int hub_master_remove(struct device *dev)
226
227 fsi_master_unregister(&hub->master);
228 fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size);
229+ of_node_put(hub->master.dev.of_node);
230+
231 return 0;
232 }
233
234--
2351.8.3.1
236