Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hsi.c
Go to the documentation of this file.
1 /*
2  * HSI core.
3  *
4  * Copyright (C) 2010 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Carlos Chinea <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  */
22 #include <linux/hsi/hsi.h>
23 #include <linux/compiler.h>
24 #include <linux/list.h>
25 #include <linux/kobject.h>
26 #include <linux/slab.h>
27 #include <linux/string.h>
28 #include <linux/notifier.h>
29 #include "hsi_core.h"
30 
31 static ssize_t modalias_show(struct device *dev,
32  struct device_attribute *a __maybe_unused, char *buf)
33 {
34  return sprintf(buf, "hsi:%s\n", dev_name(dev));
35 }
36 
37 static struct device_attribute hsi_bus_dev_attrs[] = {
38  __ATTR_RO(modalias),
40 };
41 
42 static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
43 {
44  add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev));
45 
46  return 0;
47 }
48 
49 static int hsi_bus_match(struct device *dev, struct device_driver *driver)
50 {
51  return strcmp(dev_name(dev), driver->name) == 0;
52 }
53 
54 static struct bus_type hsi_bus_type = {
55  .name = "hsi",
56  .dev_attrs = hsi_bus_dev_attrs,
57  .match = hsi_bus_match,
58  .uevent = hsi_bus_uevent,
59 };
60 
61 static void hsi_client_release(struct device *dev)
62 {
63  kfree(to_hsi_client(dev));
64 }
65 
66 static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
67 {
68  struct hsi_client *cl;
69 
70  cl = kzalloc(sizeof(*cl), GFP_KERNEL);
71  if (!cl)
72  return;
73  cl->tx_cfg = info->tx_cfg;
74  cl->rx_cfg = info->rx_cfg;
75  cl->device.bus = &hsi_bus_type;
76  cl->device.parent = &port->device;
77  cl->device.release = hsi_client_release;
78  dev_set_name(&cl->device, info->name);
79  cl->device.platform_data = info->platform_data;
80  if (info->archdata)
81  cl->device.archdata = *info->archdata;
82  if (device_register(&cl->device) < 0) {
83  pr_err("hsi: failed to register client: %s\n", info->name);
84  put_device(&cl->device);
85  }
86 }
87 
88 static void hsi_scan_board_info(struct hsi_controller *hsi)
89 {
90  struct hsi_cl_info *cl_info;
91  struct hsi_port *p;
92 
93  list_for_each_entry(cl_info, &hsi_board_list, list)
94  if (cl_info->info.hsi_id == hsi->id) {
95  p = hsi_find_port_num(hsi, cl_info->info.port);
96  if (!p)
97  continue;
98  hsi_new_client(p, &cl_info->info);
99  }
100 }
101 
102 static int hsi_remove_client(struct device *dev, void *data __maybe_unused)
103 {
104  device_unregister(dev);
105 
106  return 0;
107 }
108 
109 static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
110 {
111  device_for_each_child(dev, NULL, hsi_remove_client);
112  device_unregister(dev);
113 
114  return 0;
115 }
116 
117 static void hsi_controller_release(struct device *dev)
118 {
119  struct hsi_controller *hsi = to_hsi_controller(dev);
120 
121  kfree(hsi->port);
122  kfree(hsi);
123 }
124 
125 static void hsi_port_release(struct device *dev)
126 {
127  kfree(to_hsi_port(dev));
128 }
129 
135 {
136  device_for_each_child(&hsi->device, NULL, hsi_remove_port);
137  device_unregister(&hsi->device);
138 }
140 
148 {
149  unsigned int i;
150  int err;
151 
152  err = device_add(&hsi->device);
153  if (err < 0)
154  return err;
155  for (i = 0; i < hsi->num_ports; i++) {
156  hsi->port[i]->device.parent = &hsi->device;
157  err = device_add(&hsi->port[i]->device);
158  if (err < 0)
159  goto out;
160  }
161  /* Populate HSI bus with HSI clients */
162  hsi_scan_board_info(hsi);
163 
164  return 0;
165 out:
166  while (i-- > 0)
167  device_del(&hsi->port[i]->device);
168  device_del(&hsi->device);
169 
170  return err;
171 }
173 
181 {
182  drv->driver.bus = &hsi_bus_type;
183 
184  return driver_register(&drv->driver);
185 }
187 
188 static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)
189 {
190  return 0;
191 }
192 
193 static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
194 {
195  return 0;
196 }
197 
208 {
209  unsigned int i;
210 
211  if (!hsi)
212  return;
213 
214  for (i = 0; i < hsi->num_ports; i++)
215  if (hsi->port && hsi->port[i])
216  put_device(&hsi->port[i]->device);
217  put_device(&hsi->device);
218 }
220 
228 struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
229 {
230  struct hsi_controller *hsi;
231  struct hsi_port **port;
232  unsigned int i;
233 
234  if (!n_ports)
235  return NULL;
236 
237  hsi = kzalloc(sizeof(*hsi), flags);
238  if (!hsi)
239  return NULL;
240  port = kzalloc(sizeof(*port)*n_ports, flags);
241  if (!port) {
242  kfree(hsi);
243  return NULL;
244  }
245  hsi->num_ports = n_ports;
246  hsi->port = port;
247  hsi->device.release = hsi_controller_release;
248  device_initialize(&hsi->device);
249 
250  for (i = 0; i < n_ports; i++) {
251  port[i] = kzalloc(sizeof(**port), flags);
252  if (port[i] == NULL)
253  goto out;
254  port[i]->num = i;
255  port[i]->async = hsi_dummy_msg;
256  port[i]->setup = hsi_dummy_cl;
257  port[i]->flush = hsi_dummy_cl;
258  port[i]->start_tx = hsi_dummy_cl;
259  port[i]->stop_tx = hsi_dummy_cl;
260  port[i]->release = hsi_dummy_cl;
261  mutex_init(&port[i]->lock);
263  dev_set_name(&port[i]->device, "port%d", i);
264  hsi->port[i]->device.release = hsi_port_release;
265  device_initialize(&hsi->port[i]->device);
266  }
267 
268  return hsi;
269 out:
270  hsi_put_controller(hsi);
271 
272  return NULL;
273 }
275 
282 void hsi_free_msg(struct hsi_msg *msg)
283 {
284  if (!msg)
285  return;
286  sg_free_table(&msg->sgt);
287  kfree(msg);
288 }
290 
302 struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags)
303 {
304  struct hsi_msg *msg;
305  int err;
306 
307  msg = kzalloc(sizeof(*msg), flags);
308  if (!msg)
309  return NULL;
310 
311  if (!nents)
312  return msg;
313 
314  err = sg_alloc_table(&msg->sgt, nents, flags);
315  if (unlikely(err)) {
316  kfree(msg);
317  msg = NULL;
318  }
319 
320  return msg;
321 }
323 
343 int hsi_async(struct hsi_client *cl, struct hsi_msg *msg)
344 {
345  struct hsi_port *port = hsi_get_port(cl);
346 
347  if (!hsi_port_claimed(cl))
348  return -EACCES;
349 
350  WARN_ON_ONCE(!msg->destructor || !msg->complete);
351  msg->cl = cl;
352 
353  return port->async(msg);
354 }
356 
364 int hsi_claim_port(struct hsi_client *cl, unsigned int share)
365 {
366  struct hsi_port *port = hsi_get_port(cl);
367  int err = 0;
368 
369  mutex_lock(&port->lock);
370  if ((port->claimed) && (!port->shared || !share)) {
371  err = -EBUSY;
372  goto out;
373  }
374  if (!try_module_get(to_hsi_controller(port->device.parent)->owner)) {
375  err = -ENODEV;
376  goto out;
377  }
378  port->claimed++;
379  port->shared = !!share;
380  cl->pclaimed = 1;
381 out:
382  mutex_unlock(&port->lock);
383 
384  return err;
385 }
387 
392 void hsi_release_port(struct hsi_client *cl)
393 {
394  struct hsi_port *port = hsi_get_port(cl);
395 
396  mutex_lock(&port->lock);
397  /* Allow HW driver to do some cleanup */
398  port->release(cl);
399  if (cl->pclaimed)
400  port->claimed--;
401  BUG_ON(port->claimed < 0);
402  cl->pclaimed = 0;
403  if (!port->claimed)
404  port->shared = 0;
405  module_put(to_hsi_controller(port->device.parent)->owner);
406  mutex_unlock(&port->lock);
407 }
409 
410 static int hsi_event_notifier_call(struct notifier_block *nb,
411  unsigned long event, void *data __maybe_unused)
412 {
413  struct hsi_client *cl = container_of(nb, struct hsi_client, nb);
414 
415  (*cl->ehandler)(cl, event);
416 
417  return 0;
418 }
419 
433  void (*handler)(struct hsi_client *, unsigned long))
434 {
435  struct hsi_port *port = hsi_get_port(cl);
436 
437  if (!handler || cl->ehandler)
438  return -EINVAL;
439  if (!hsi_port_claimed(cl))
440  return -EACCES;
441  cl->ehandler = handler;
442  cl->nb.notifier_call = hsi_event_notifier_call;
443 
444  return atomic_notifier_chain_register(&port->n_head, &cl->nb);
445 }
447 
458 {
459  struct hsi_port *port = hsi_get_port(cl);
460  int err;
461 
462  WARN_ON(!hsi_port_claimed(cl));
463 
464  err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb);
465  if (!err)
466  cl->ehandler = NULL;
467 
468  return err;
469 }
471 
487 int hsi_event(struct hsi_port *port, unsigned long event)
488 {
489  return atomic_notifier_call_chain(&port->n_head, event, NULL);
490 }
492 
493 static int __init hsi_init(void)
494 {
495  return bus_register(&hsi_bus_type);
496 }
497 postcore_initcall(hsi_init);
498 
499 static void __exit hsi_exit(void)
500 {
501  bus_unregister(&hsi_bus_type);
502 }
503 module_exit(hsi_exit);
504 
505 MODULE_AUTHOR("Carlos Chinea <[email protected]>");
506 MODULE_DESCRIPTION("High-speed Synchronous Serial Interface (HSI) framework");
507 MODULE_LICENSE("GPL v2");