blob: 39bc9ffe27261bc7c002b8e836580774c0120058 [file] [log] [blame]
Pratik Patela20572b2012-12-02 20:33:50 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Pratik Patel74929432011-12-26 12:03:41 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patelbf3e77442012-03-18 18:30:43 -070021#include <linux/export.h>
Pratik Patelb84ef9d2012-05-24 14:01:43 -070022#include <linux/slab.h>
Pratik Patel0a7edd32012-06-08 09:31:55 -070023#include <linux/semaphore.h>
Pratik Patel27086d92012-05-17 23:21:43 -070024#include <linux/clk.h>
Pratik Patel1746b8f2012-06-02 21:11:41 -070025#include <linux/coresight.h>
Pratik Patel74929432011-12-26 12:03:41 -080026
Pratik Patel1746b8f2012-06-02 21:11:41 -070027#include "coresight-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080028
Pratik Patel0a7edd32012-06-08 09:31:55 -070029#define NO_SINK (-1)
Pratik Patel1403f2a2012-03-21 10:10:00 -070030
Pratik Patel0a7edd32012-06-08 09:31:55 -070031static int curr_sink = NO_SINK;
Pratik Patel6fb38342012-06-03 14:51:38 -070032static LIST_HEAD(coresight_orph_conns);
Pratik Patel6fb38342012-06-03 14:51:38 -070033static LIST_HEAD(coresight_devs);
Pratik Patel0a7edd32012-06-08 09:31:55 -070034static DEFINE_SEMAPHORE(coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070035
Pratik Patel0a7edd32012-06-08 09:31:55 -070036static int coresight_find_link_inport(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -070037{
38 int i;
Pratik Patel0a7edd32012-06-08 09:31:55 -070039 struct coresight_device *parent;
Pratik Patel6fb38342012-06-03 14:51:38 -070040 struct coresight_connection *conn;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070041
Pratik Patel0a7edd32012-06-08 09:31:55 -070042 parent = container_of(csdev->path_link.next, struct coresight_device,
43 path_link);
44 for (i = 0; i < parent->nr_conns; i++) {
45 conn = &parent->conns[i];
46 if (conn->child_dev == csdev)
47 return conn->child_port;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070048 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070049
50 pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
51 parent->id, csdev->id);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070052 return 0;
Pratik Patel0a7edd32012-06-08 09:31:55 -070053}
54
55static int coresight_find_link_outport(struct coresight_device *csdev)
56{
57 int i;
58 struct coresight_device *child;
59 struct coresight_connection *conn;
60
61 child = container_of(csdev->path_link.prev, struct coresight_device,
62 path_link);
63 for (i = 0; i < csdev->nr_conns; i++) {
64 conn = &csdev->conns[i];
65 if (conn->child_dev == child)
66 return conn->outport;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070067 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070068
69 pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
70 csdev->id, child->id);
71 return 0;
72}
73
74static int coresight_enable_sink(struct coresight_device *csdev)
75{
76 int ret;
77
78 if (csdev->refcnt.sink_refcnt == 0) {
79 if (csdev->ops->sink_ops->enable) {
80 ret = csdev->ops->sink_ops->enable(csdev);
81 if (ret)
82 goto err;
83 csdev->enable = true;
84 }
85 }
86 csdev->refcnt.sink_refcnt++;
87
88 return 0;
89err:
90 return ret;
91}
92
93static void coresight_disable_sink(struct coresight_device *csdev)
94{
95 if (csdev->refcnt.sink_refcnt == 1) {
96 if (csdev->ops->sink_ops->disable) {
97 csdev->ops->sink_ops->disable(csdev);
98 csdev->enable = false;
99 }
100 }
101 csdev->refcnt.sink_refcnt--;
102}
103
104static int coresight_enable_link(struct coresight_device *csdev)
105{
106 int ret;
107 int link_subtype;
108 int refport, inport, outport;
109
110 inport = coresight_find_link_inport(csdev);
111 outport = coresight_find_link_outport(csdev);
112
113 link_subtype = csdev->subtype.link_subtype;
114 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
115 refport = inport;
116 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
117 refport = outport;
118 else
119 refport = 0;
120
121 if (csdev->refcnt.link_refcnts[refport] == 0) {
122 if (csdev->ops->link_ops->enable) {
123 ret = csdev->ops->link_ops->enable(csdev, inport,
124 outport);
125 if (ret)
126 goto err;
127 csdev->enable = true;
128 }
129 }
130 csdev->refcnt.link_refcnts[refport]++;
131
132 return 0;
133err:
134 return ret;
135}
136
137static void coresight_disable_link(struct coresight_device *csdev)
138{
139 int link_subtype;
140 int refport, inport, outport;
141
142 inport = coresight_find_link_inport(csdev);
143 outport = coresight_find_link_outport(csdev);
144
145 link_subtype = csdev->subtype.link_subtype;
146 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
147 refport = inport;
148 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
149 refport = outport;
150 else
151 refport = 0;
152
153 if (csdev->refcnt.link_refcnts[refport] == 1) {
154 if (csdev->ops->link_ops->disable) {
155 csdev->ops->link_ops->disable(csdev, inport, outport);
156 csdev->enable = false;
157 }
158 }
159 csdev->refcnt.link_refcnts[refport]--;
160}
161
162static int coresight_enable_source(struct coresight_device *csdev)
163{
164 int ret;
165
166 if (csdev->refcnt.source_refcnt == 0) {
167 if (csdev->ops->source_ops->enable) {
168 ret = csdev->ops->source_ops->enable(csdev);
169 if (ret)
170 goto err;
171 csdev->enable = true;
172 }
173 }
174 csdev->refcnt.source_refcnt++;
175
176 return 0;
177err:
178 return ret;
179}
180
181static void coresight_disable_source(struct coresight_device *csdev)
182{
183 if (csdev->refcnt.source_refcnt == 1) {
184 if (csdev->ops->source_ops->disable) {
185 csdev->ops->source_ops->disable(csdev);
186 csdev->enable = false;
187 }
188 }
189 csdev->refcnt.source_refcnt--;
190}
191
192static struct list_head *coresight_build_path(struct coresight_device *csdev,
193 struct list_head *path)
194{
195 int i;
196 struct list_head *p;
197 struct coresight_connection *conn;
198
199 if (csdev->id == curr_sink) {
200 list_add_tail(&csdev->path_link, path);
201 return path;
202 }
203
204 for (i = 0; i < csdev->nr_conns; i++) {
205 conn = &csdev->conns[i];
206 p = coresight_build_path(conn->child_dev, path);
207 if (p) {
208 list_add_tail(&csdev->path_link, p);
209 return p;
210 }
211 }
212 return NULL;
213}
214
215static void coresight_release_path(struct list_head *path)
216{
217 struct coresight_device *cd, *temp;
218
219 list_for_each_entry_safe(cd, temp, path, path_link)
220 list_del(&cd->path_link);
221}
222
223static int coresight_enable_path(struct list_head *path, bool incl_source)
224{
225 int ret = 0;
226 struct coresight_device *cd;
227
228 list_for_each_entry(cd, path, path_link) {
229 if (cd == list_first_entry(path, struct coresight_device,
230 path_link)) {
231 ret = coresight_enable_sink(cd);
232 } else if (list_is_last(&cd->path_link, path)) {
233 if (incl_source)
234 ret = coresight_enable_source(cd);
235 } else {
236 ret = coresight_enable_link(cd);
237 }
238 if (ret)
239 goto err;
240 }
241 return 0;
242err:
243 list_for_each_entry_continue_reverse(cd, path, path_link) {
244 if (cd == list_first_entry(path, struct coresight_device,
245 path_link)) {
246 coresight_disable_sink(cd);
247 } else if (list_is_last(&cd->path_link, path)) {
248 if (incl_source)
249 coresight_disable_source(cd);
250 } else {
251 coresight_disable_link(cd);
252 }
253 }
254 return ret;
255}
256
257static void coresight_disable_path(struct list_head *path, bool incl_source)
258{
259 struct coresight_device *cd;
260
261 list_for_each_entry(cd, path, path_link) {
262 if (cd == list_first_entry(path, struct coresight_device,
263 path_link)) {
264 coresight_disable_sink(cd);
265 } else if (list_is_last(&cd->path_link, path)) {
266 if (incl_source)
267 coresight_disable_source(cd);
268 } else {
269 coresight_disable_link(cd);
270 }
271 }
272}
273
274static int coresight_switch_sink(struct coresight_device *csdev)
275{
276 int ret = 0;
277 LIST_HEAD(path);
278 struct coresight_device *cd;
279
280 if (IS_ERR_OR_NULL(csdev))
281 return -EINVAL;
282
283 down(&coresight_mutex);
284 if (csdev->id == curr_sink)
285 goto out;
286
287 list_for_each_entry(cd, &coresight_devs, dev_link) {
288 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
289 coresight_build_path(cd, &path);
290 coresight_disable_path(&path, false);
291 coresight_release_path(&path);
292 }
293 }
294 curr_sink = csdev->id;
295 list_for_each_entry(cd, &coresight_devs, dev_link) {
296 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
297 coresight_build_path(cd, &path);
298 ret = coresight_enable_path(&path, false);
299 coresight_release_path(&path);
300 if (ret)
301 goto err;
302 }
303 }
304out:
305 up(&coresight_mutex);
306 return 0;
307err:
308 list_for_each_entry(cd, &coresight_devs, dev_link) {
309 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
310 coresight_disable_source(cd);
311 }
312 pr_err("coresight: sink switch failed, sources disabled; try again\n");
313 return ret;
314}
315
316int coresight_enable(struct coresight_device *csdev)
317{
318 int ret = 0;
319 LIST_HEAD(path);
320
321 if (IS_ERR_OR_NULL(csdev))
322 return -EINVAL;
323
324 down(&coresight_mutex);
325 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
326 ret = -EINVAL;
327 pr_err("coresight: wrong device type in %s\n", __func__);
328 goto out;
329 }
330 if (csdev->enable)
331 goto out;
332
333 coresight_build_path(csdev, &path);
334 ret = coresight_enable_path(&path, true);
335 coresight_release_path(&path);
336 if (ret)
337 pr_err("coresight: enable failed\n");
338out:
339 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700340 return ret;
341}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700342EXPORT_SYMBOL_GPL(coresight_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700343
Pratik Patel0a7edd32012-06-08 09:31:55 -0700344void coresight_disable(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700345{
Pratik Patel0a7edd32012-06-08 09:31:55 -0700346 LIST_HEAD(path);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700347
Pratik Patel0a7edd32012-06-08 09:31:55 -0700348 if (IS_ERR_OR_NULL(csdev))
349 return;
350
351 down(&coresight_mutex);
352 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
353 pr_err("coresight: wrong device type in %s\n", __func__);
354 goto out;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700355 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700356 if (!csdev->enable)
357 goto out;
358
359 coresight_build_path(csdev, &path);
360 coresight_disable_path(&path, true);
361 coresight_release_path(&path);
362out:
363 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700364}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700365EXPORT_SYMBOL_GPL(coresight_disable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700366
Pratik Patelcf7d0452012-07-02 13:57:20 -0700367void coresight_abort(void)
368{
369 struct coresight_device *cd;
370
371 if (down_trylock(&coresight_mutex)) {
372 pr_err("coresight: abort could not be processed\n");
373 return;
374 }
375 if (curr_sink == NO_SINK)
376 goto out;
377
378 list_for_each_entry(cd, &coresight_devs, dev_link) {
379 if (cd->id == curr_sink) {
Pratik Patel00474562012-09-26 12:39:29 -0700380 if (cd->enable && cd->ops->sink_ops->abort) {
Pratik Patelcf7d0452012-07-02 13:57:20 -0700381 cd->ops->sink_ops->abort(cd);
Pratik Patel00474562012-09-26 12:39:29 -0700382 cd->enable = false;
383 }
Pratik Patelcf7d0452012-07-02 13:57:20 -0700384 }
385 }
386out:
387 up(&coresight_mutex);
388}
389EXPORT_SYMBOL_GPL(coresight_abort);
390
Pratik Patel6fb38342012-06-03 14:51:38 -0700391static ssize_t coresight_show_type(struct device *dev,
392 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700393{
394 return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
395}
396
Pratik Patel6fb38342012-06-03 14:51:38 -0700397static struct device_attribute coresight_dev_attrs[] = {
398 __ATTR(type, S_IRUGO, coresight_show_type, NULL),
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700399 { },
400};
401
Pratik Patel6fb38342012-06-03 14:51:38 -0700402struct bus_type coresight_bus_type = {
403 .name = "coresight",
404 .dev_attrs = coresight_dev_attrs,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700405};
406
Pratik Patel0a7edd32012-06-08 09:31:55 -0700407static ssize_t coresight_show_curr_sink(struct device *dev,
408 struct device_attribute *attr,
409 char *buf)
410{
411 struct coresight_device *csdev = to_coresight_device(dev);
412
413 return scnprintf(buf, PAGE_SIZE, "%u\n",
414 csdev->id == curr_sink ? 1 : 0);
415}
416
417static ssize_t coresight_store_curr_sink(struct device *dev,
418 struct device_attribute *attr,
419 const char *buf, size_t size)
420{
421 int ret = 0;
422 unsigned long val;
423 struct coresight_device *csdev = to_coresight_device(dev);
424
425 if (sscanf(buf, "%lx", &val) != 1)
426 return -EINVAL;
427
428 if (val)
429 ret = coresight_switch_sink(csdev);
430 else
431 ret = -EINVAL;
432
433 if (ret)
434 return ret;
435 return size;
436}
437static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
438 coresight_store_curr_sink);
439
Pratik Patel6fb38342012-06-03 14:51:38 -0700440static ssize_t coresight_show_enable(struct device *dev,
441 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700442{
Pratik Patel6fb38342012-06-03 14:51:38 -0700443 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700444
445 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
446}
447
Pratik Patel6fb38342012-06-03 14:51:38 -0700448static ssize_t coresight_store_enable(struct device *dev,
449 struct device_attribute *attr,
450 const char *buf, size_t size)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700451{
452 int ret = 0;
453 unsigned long val;
Pratik Patel6fb38342012-06-03 14:51:38 -0700454 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700455
456 if (sscanf(buf, "%lx", &val) != 1)
457 return -EINVAL;
458
459 if (val)
Pratik Patel0a7edd32012-06-08 09:31:55 -0700460 ret = coresight_enable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700461 else
Pratik Patel0a7edd32012-06-08 09:31:55 -0700462 coresight_disable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700463
464 if (ret)
465 return ret;
466 return size;
467}
Pratik Patel6fb38342012-06-03 14:51:38 -0700468static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
469 coresight_store_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700470
Pratik Patel0a7edd32012-06-08 09:31:55 -0700471static struct attribute *coresight_attrs_sink[] = {
472 &dev_attr_curr_sink.attr,
473 NULL,
474};
475
476static struct attribute_group coresight_attr_grp_sink = {
477 .attrs = coresight_attrs_sink,
478};
479
480static const struct attribute_group *coresight_attr_grps_sink[] = {
481 &coresight_attr_grp_sink,
482 NULL,
483};
484
485static struct attribute *coresight_attrs_source[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700486 &dev_attr_enable.attr,
487 NULL,
488};
489
Pratik Patel0a7edd32012-06-08 09:31:55 -0700490static struct attribute_group coresight_attr_grp_source = {
491 .attrs = coresight_attrs_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700492};
493
Pratik Patel0a7edd32012-06-08 09:31:55 -0700494static const struct attribute_group *coresight_attr_grps_source[] = {
495 &coresight_attr_grp_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700496 NULL,
497};
498
Pratik Patel0a7edd32012-06-08 09:31:55 -0700499static struct device_type coresight_dev_type[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700500 {
Pratik Patelb8bb4032012-07-22 23:09:11 -0700501 .name = "none",
502 },
503 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700504 .name = "sink",
505 .groups = coresight_attr_grps_sink,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700506 },
507 {
508 .name = "link",
509 },
510 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700511 .name = "linksink",
512 .groups = coresight_attr_grps_sink,
513 },
514 {
515 .name = "source",
516 .groups = coresight_attr_grps_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700517 },
518};
519
Pratik Patel6fb38342012-06-03 14:51:38 -0700520static void coresight_device_release(struct device *dev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700521{
Pratik Patel6fb38342012-06-03 14:51:38 -0700522 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700523 kfree(csdev);
524}
525
Pratik Patel6fb38342012-06-03 14:51:38 -0700526static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700527{
Pratik Patel6fb38342012-06-03 14:51:38 -0700528 struct coresight_connection *conn, *temp;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700529
Pratik Patel6fb38342012-06-03 14:51:38 -0700530 list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700531 if (conn->child_id == csdev->id) {
532 conn->child_dev = csdev;
533 list_del(&conn->link);
534 }
535 }
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700536}
537
Pratik Patel6fb38342012-06-03 14:51:38 -0700538static void coresight_fixup_device_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700539{
540 int i;
Pratik Patel6fb38342012-06-03 14:51:38 -0700541 struct coresight_device *cd;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700542 bool found;
543
544 for (i = 0; i < csdev->nr_conns; i++) {
545 found = false;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700546 list_for_each_entry(cd, &coresight_devs, dev_link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700547 if (csdev->conns[i].child_id == cd->id) {
548 csdev->conns[i].child_dev = cd;
549 found = true;
550 break;
551 }
552 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700553 if (!found)
Pratik Patel6fb38342012-06-03 14:51:38 -0700554 list_add_tail(&csdev->conns[i].link,
555 &coresight_orph_conns);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700556 }
557}
558
Pratik Patel6fb38342012-06-03 14:51:38 -0700559struct coresight_device *coresight_register(struct coresight_desc *desc)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700560{
561 int i;
562 int ret;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700563 int link_subtype;
564 int nr_refcnts;
565 int *refcnts = NULL;
Pratik Patel6fb38342012-06-03 14:51:38 -0700566 struct coresight_device *csdev;
567 struct coresight_connection *conns;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700568
Pratik Patela20572b2012-12-02 20:33:50 -0800569 if (IS_ERR_OR_NULL(desc))
570 return ERR_PTR(-EINVAL);
571
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700572 csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
573 if (!csdev) {
574 ret = -ENOMEM;
575 goto err_kzalloc_csdev;
576 }
577
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700578 csdev->id = desc->pdata->id;
579
Pratik Patel0a7edd32012-06-08 09:31:55 -0700580 if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
581 desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
582 link_subtype = desc->subtype.link_subtype;
583 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
584 nr_refcnts = desc->pdata->nr_inports;
585 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
586 nr_refcnts = desc->pdata->nr_outports;
587 else
588 nr_refcnts = 1;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700589
Pratik Patel0a7edd32012-06-08 09:31:55 -0700590 refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
591 if (!refcnts) {
592 ret = -ENOMEM;
593 goto err_kzalloc_refcnts;
594 }
595 csdev->refcnt.link_refcnts = refcnts;
596 }
597
598 csdev->nr_conns = desc->pdata->nr_outports;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700599 conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
600 if (!conns) {
601 ret = -ENOMEM;
602 goto err_kzalloc_conns;
603 }
604 for (i = 0; i < csdev->nr_conns; i++) {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700605 conns[i].outport = desc->pdata->outports[i];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700606 conns[i].child_id = desc->pdata->child_ids[i];
607 conns[i].child_port = desc->pdata->child_ports[i];
608 }
609 csdev->conns = conns;
610
Pratik Patel0a7edd32012-06-08 09:31:55 -0700611 csdev->type = desc->type;
612 csdev->subtype = desc->subtype;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700613 csdev->ops = desc->ops;
614 csdev->owner = desc->owner;
615
Pratik Patel6fb38342012-06-03 14:51:38 -0700616 csdev->dev.type = &coresight_dev_type[desc->type];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700617 csdev->dev.groups = desc->groups;
618 csdev->dev.parent = desc->dev;
Pratik Patel6fb38342012-06-03 14:51:38 -0700619 csdev->dev.bus = &coresight_bus_type;
620 csdev->dev.release = coresight_device_release;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700621 dev_set_name(&csdev->dev, "%s", desc->pdata->name);
622
Pratik Patel0a7edd32012-06-08 09:31:55 -0700623 down(&coresight_mutex);
624 if (desc->pdata->default_sink) {
625 if (curr_sink == NO_SINK) {
626 curr_sink = csdev->id;
627 } else {
628 ret = -EINVAL;
629 goto err_default_sink;
630 }
631 }
632
Pratik Patel6fb38342012-06-03 14:51:38 -0700633 coresight_fixup_device_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700634 ret = device_register(&csdev->dev);
635 if (ret)
636 goto err_dev_reg;
Pratik Patel6fb38342012-06-03 14:51:38 -0700637 coresight_fixup_orphan_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700638
Pratik Patel0a7edd32012-06-08 09:31:55 -0700639 list_add_tail(&csdev->dev_link, &coresight_devs);
640 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700641
642 return csdev;
643err_dev_reg:
644 put_device(&csdev->dev);
Pratik Patel0a7edd32012-06-08 09:31:55 -0700645err_default_sink:
646 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700647 kfree(conns);
648err_kzalloc_conns:
Pratik Patel0a7edd32012-06-08 09:31:55 -0700649 kfree(refcnts);
650err_kzalloc_refcnts:
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700651 kfree(csdev);
652err_kzalloc_csdev:
653 return ERR_PTR(ret);
654}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700655EXPORT_SYMBOL_GPL(coresight_register);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700656
Pratik Patel6fb38342012-06-03 14:51:38 -0700657void coresight_unregister(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700658{
659 if (IS_ERR_OR_NULL(csdev))
660 return;
661
662 if (get_device(&csdev->dev)) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700663 device_unregister(&csdev->dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700664 put_device(&csdev->dev);
665 }
666}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700667EXPORT_SYMBOL_GPL(coresight_unregister);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700668
Pratik Patel6fb38342012-06-03 14:51:38 -0700669static int __init coresight_init(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700670{
Pratik Patel6fb38342012-06-03 14:51:38 -0700671 return bus_register(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700672}
Pratik Patel6fb38342012-06-03 14:51:38 -0700673subsys_initcall(coresight_init);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700674
Pratik Patel6fb38342012-06-03 14:51:38 -0700675static void __exit coresight_exit(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700676{
Pratik Patel6fb38342012-06-03 14:51:38 -0700677 bus_unregister(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700678}
Pratik Patel6fb38342012-06-03 14:51:38 -0700679module_exit(coresight_exit);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700680
681MODULE_LICENSE("GPL v2");