aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hsi
diff options
context:
space:
mode:
authorSebastian Reichel <sre@kernel.org>2014-03-28 17:59:43 -0400
committerSebastian Reichel <sre@kernel.org>2014-05-15 18:54:45 -0400
commita2aa24734d9dbbd3b9062c2459936c336278fa6a (patch)
treec398938da3956b80397f3154badbec24134739b9 /drivers/hsi
parent8491451024bcfabdcebd772ce9ec2fc5757acd42 (diff)
HSI: Add common DT binding for HSI client devices
Implement and document generic DT bindings for HSI clients. Signed-off-by: Sebastian Reichel <sre@kernel.org> Reviewed-by: Pavel Machek <pavel@ucw.cz> Tested-By: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
Diffstat (limited to 'drivers/hsi')
-rw-r--r--drivers/hsi/hsi.c208
1 files changed, 206 insertions, 2 deletions
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index 834a2d6b444e..fe9371271ce2 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -26,6 +26,8 @@
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/string.h> 27#include <linux/string.h>
28#include <linux/notifier.h> 28#include <linux/notifier.h>
29#include <linux/of.h>
30#include <linux/of_device.h>
29#include "hsi_core.h" 31#include "hsi_core.h"
30 32
31static ssize_t modalias_show(struct device *dev, 33static ssize_t modalias_show(struct device *dev,
@@ -50,7 +52,13 @@ static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
50 52
51static int hsi_bus_match(struct device *dev, struct device_driver *driver) 53static int hsi_bus_match(struct device *dev, struct device_driver *driver)
52{ 54{
53 return strcmp(dev_name(dev), driver->name) == 0; 55 if (of_driver_match_device(dev, driver))
56 return true;
57
58 if (strcmp(dev_name(dev), driver->name) == 0)
59 return true;
60
61 return false;
54} 62}
55 63
56static struct bus_type hsi_bus_type = { 64static struct bus_type hsi_bus_type = {
@@ -123,6 +131,202 @@ static void hsi_scan_board_info(struct hsi_controller *hsi)
123 } 131 }
124} 132}
125 133
134#ifdef CONFIG_OF
135static struct hsi_board_info hsi_char_dev_info = {
136 .name = "hsi_char",
137};
138
139static int hsi_of_property_parse_mode(struct device_node *client, char *name,
140 unsigned int *result)
141{
142 const char *mode;
143 int err;
144
145 err = of_property_read_string(client, name, &mode);
146 if (err < 0)
147 return err;
148
149 if (strcmp(mode, "stream") == 0)
150 *result = HSI_MODE_STREAM;
151 else if (strcmp(mode, "frame") == 0)
152 *result = HSI_MODE_FRAME;
153 else
154 return -EINVAL;
155
156 return 0;
157}
158
159static int hsi_of_property_parse_flow(struct device_node *client, char *name,
160 unsigned int *result)
161{
162 const char *flow;
163 int err;
164
165 err = of_property_read_string(client, name, &flow);
166 if (err < 0)
167 return err;
168
169 if (strcmp(flow, "synchronized") == 0)
170 *result = HSI_FLOW_SYNC;
171 else if (strcmp(flow, "pipeline") == 0)
172 *result = HSI_FLOW_PIPE;
173 else
174 return -EINVAL;
175
176 return 0;
177}
178
179static int hsi_of_property_parse_arb_mode(struct device_node *client,
180 char *name, unsigned int *result)
181{
182 const char *arb_mode;
183 int err;
184
185 err = of_property_read_string(client, name, &arb_mode);
186 if (err < 0)
187 return err;
188
189 if (strcmp(arb_mode, "round-robin") == 0)
190 *result = HSI_ARB_RR;
191 else if (strcmp(arb_mode, "priority") == 0)
192 *result = HSI_ARB_PRIO;
193 else
194 return -EINVAL;
195
196 return 0;
197}
198
199static void hsi_add_client_from_dt(struct hsi_port *port,
200 struct device_node *client)
201{
202 struct hsi_client *cl;
203 struct hsi_channel channel;
204 struct property *prop;
205 char name[32];
206 int length, cells, err, i, max_chan, mode;
207
208 cl = kzalloc(sizeof(*cl), GFP_KERNEL);
209 if (!cl)
210 return;
211
212 err = of_modalias_node(client, name, sizeof(name));
213 if (err)
214 goto err;
215
216 dev_set_name(&cl->device, "%s", name);
217
218 err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
219 if (err) {
220 err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
221 &cl->rx_cfg.mode);
222 if (err)
223 goto err;
224
225 err = hsi_of_property_parse_mode(client, "hsi-tx-mode",
226 &cl->tx_cfg.mode);
227 if (err)
228 goto err;
229 } else {
230 cl->rx_cfg.mode = mode;
231 cl->tx_cfg.mode = mode;
232 }
233
234 err = of_property_read_u32(client, "hsi-speed-kbps",
235 &cl->tx_cfg.speed);
236 if (err)
237 goto err;
238 cl->rx_cfg.speed = cl->tx_cfg.speed;
239
240 err = hsi_of_property_parse_flow(client, "hsi-flow",
241 &cl->rx_cfg.flow);
242 if (err)
243 goto err;
244
245 err = hsi_of_property_parse_arb_mode(client, "hsi-arb-mode",
246 &cl->rx_cfg.arb_mode);
247 if (err)
248 goto err;
249
250 prop = of_find_property(client, "hsi-channel-ids", &length);
251 if (!prop) {
252 err = -EINVAL;
253 goto err;
254 }
255
256 cells = length / sizeof(u32);
257
258 cl->rx_cfg.num_channels = cells;
259 cl->tx_cfg.num_channels = cells;
260
261 cl->rx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL);
262 if (!cl->rx_cfg.channels) {
263 err = -ENOMEM;
264 goto err;
265 }
266
267 cl->tx_cfg.channels = kzalloc(cells * sizeof(channel), GFP_KERNEL);
268 if (!cl->tx_cfg.channels) {
269 err = -ENOMEM;
270 goto err2;
271 }
272
273 max_chan = 0;
274 for (i = 0; i < cells; i++) {
275 err = of_property_read_u32_index(client, "hsi-channel-ids", i,
276 &channel.id);
277 if (err)
278 goto err3;
279
280 err = of_property_read_string_index(client, "hsi-channel-names",
281 i, &channel.name);
282 if (err)
283 channel.name = NULL;
284
285 if (channel.id > max_chan)
286 max_chan = channel.id;
287
288 cl->rx_cfg.channels[i] = channel;
289 cl->tx_cfg.channels[i] = channel;
290 }
291
292 cl->rx_cfg.num_hw_channels = max_chan + 1;
293 cl->tx_cfg.num_hw_channels = max_chan + 1;
294
295 cl->device.bus = &hsi_bus_type;
296 cl->device.parent = &port->device;
297 cl->device.release = hsi_client_release;
298 cl->device.of_node = client;
299
300 if (device_register(&cl->device) < 0) {
301 pr_err("hsi: failed to register client: %s\n", name);
302 put_device(&cl->device);
303 goto err3;
304 }
305
306 return;
307
308err3:
309 kfree(cl->tx_cfg.channels);
310err2:
311 kfree(cl->rx_cfg.channels);
312err:
313 kfree(cl);
314 pr_err("hsi client: missing or incorrect of property: err=%d\n", err);
315}
316
317void hsi_add_clients_from_dt(struct hsi_port *port, struct device_node *clients)
318{
319 struct device_node *child;
320
321 /* register hsi-char device */
322 hsi_new_client(port, &hsi_char_dev_info);
323
324 for_each_available_child_of_node(clients, child)
325 hsi_add_client_from_dt(port, child);
326}
327EXPORT_SYMBOL_GPL(hsi_add_clients_from_dt);
328#endif
329
126int hsi_remove_client(struct device *dev, void *data __maybe_unused) 330int hsi_remove_client(struct device *dev, void *data __maybe_unused)
127{ 331{
128 device_unregister(dev); 332 device_unregister(dev);
@@ -505,7 +709,7 @@ int hsi_unregister_port_event(struct hsi_client *cl)
505EXPORT_SYMBOL_GPL(hsi_unregister_port_event); 709EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
506 710
507/** 711/**
508 * hsi_event -Notifies clients about port events 712 * hsi_event - Notifies clients about port events
509 * @port: Port where the event occurred 713 * @port: Port where the event occurred
510 * @event: The event type 714 * @event: The event type
511 * 715 *