blob: 0c6b56ad1149e317b27f26cc6ba469c0405e58b3 [file] [log] [blame]
Pratik Patel74929432011-12-26 12:03:41 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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
30#define NO_SINK (-1)
Pratik Patel1403f2a2012-03-21 10:10:00 -070031
Pratik Patel74929432011-12-26 12:03:41 -080032
Pratik Patel0a7edd32012-06-08 09:31:55 -070033static int curr_sink = NO_SINK;
Pratik Patel6fb38342012-06-03 14:51:38 -070034static LIST_HEAD(coresight_orph_conns);
Pratik Patel6fb38342012-06-03 14:51:38 -070035static LIST_HEAD(coresight_devs);
Pratik Patel0a7edd32012-06-08 09:31:55 -070036static DEFINE_SEMAPHORE(coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070037
38
Pratik Patel0a7edd32012-06-08 09:31:55 -070039static int coresight_find_link_inport(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -070040{
41 int i;
Pratik Patel0a7edd32012-06-08 09:31:55 -070042 struct coresight_device *parent;
Pratik Patel6fb38342012-06-03 14:51:38 -070043 struct coresight_connection *conn;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070044
Pratik Patel0a7edd32012-06-08 09:31:55 -070045 parent = container_of(csdev->path_link.next, struct coresight_device,
46 path_link);
47 for (i = 0; i < parent->nr_conns; i++) {
48 conn = &parent->conns[i];
49 if (conn->child_dev == csdev)
50 return conn->child_port;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070051 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070052
53 pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
54 parent->id, csdev->id);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070055 return 0;
Pratik Patel0a7edd32012-06-08 09:31:55 -070056}
57
58static int coresight_find_link_outport(struct coresight_device *csdev)
59{
60 int i;
61 struct coresight_device *child;
62 struct coresight_connection *conn;
63
64 child = container_of(csdev->path_link.prev, struct coresight_device,
65 path_link);
66 for (i = 0; i < csdev->nr_conns; i++) {
67 conn = &csdev->conns[i];
68 if (conn->child_dev == child)
69 return conn->outport;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070070 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070071
72 pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
73 csdev->id, child->id);
74 return 0;
75}
76
77static int coresight_enable_sink(struct coresight_device *csdev)
78{
79 int ret;
80
81 if (csdev->refcnt.sink_refcnt == 0) {
82 if (csdev->ops->sink_ops->enable) {
83 ret = csdev->ops->sink_ops->enable(csdev);
84 if (ret)
85 goto err;
86 csdev->enable = true;
87 }
88 }
89 csdev->refcnt.sink_refcnt++;
90
91 return 0;
92err:
93 return ret;
94}
95
96static void coresight_disable_sink(struct coresight_device *csdev)
97{
98 if (csdev->refcnt.sink_refcnt == 1) {
99 if (csdev->ops->sink_ops->disable) {
100 csdev->ops->sink_ops->disable(csdev);
101 csdev->enable = false;
102 }
103 }
104 csdev->refcnt.sink_refcnt--;
105}
106
107static int coresight_enable_link(struct coresight_device *csdev)
108{
109 int ret;
110 int link_subtype;
111 int refport, inport, outport;
112
113 inport = coresight_find_link_inport(csdev);
114 outport = coresight_find_link_outport(csdev);
115
116 link_subtype = csdev->subtype.link_subtype;
117 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
118 refport = inport;
119 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
120 refport = outport;
121 else
122 refport = 0;
123
124 if (csdev->refcnt.link_refcnts[refport] == 0) {
125 if (csdev->ops->link_ops->enable) {
126 ret = csdev->ops->link_ops->enable(csdev, inport,
127 outport);
128 if (ret)
129 goto err;
130 csdev->enable = true;
131 }
132 }
133 csdev->refcnt.link_refcnts[refport]++;
134
135 return 0;
136err:
137 return ret;
138}
139
140static void coresight_disable_link(struct coresight_device *csdev)
141{
142 int link_subtype;
143 int refport, inport, outport;
144
145 inport = coresight_find_link_inport(csdev);
146 outport = coresight_find_link_outport(csdev);
147
148 link_subtype = csdev->subtype.link_subtype;
149 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
150 refport = inport;
151 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
152 refport = outport;
153 else
154 refport = 0;
155
156 if (csdev->refcnt.link_refcnts[refport] == 1) {
157 if (csdev->ops->link_ops->disable) {
158 csdev->ops->link_ops->disable(csdev, inport, outport);
159 csdev->enable = false;
160 }
161 }
162 csdev->refcnt.link_refcnts[refport]--;
163}
164
165static int coresight_enable_source(struct coresight_device *csdev)
166{
167 int ret;
168
169 if (csdev->refcnt.source_refcnt == 0) {
170 if (csdev->ops->source_ops->enable) {
171 ret = csdev->ops->source_ops->enable(csdev);
172 if (ret)
173 goto err;
174 csdev->enable = true;
175 }
176 }
177 csdev->refcnt.source_refcnt++;
178
179 return 0;
180err:
181 return ret;
182}
183
184static void coresight_disable_source(struct coresight_device *csdev)
185{
186 if (csdev->refcnt.source_refcnt == 1) {
187 if (csdev->ops->source_ops->disable) {
188 csdev->ops->source_ops->disable(csdev);
189 csdev->enable = false;
190 }
191 }
192 csdev->refcnt.source_refcnt--;
193}
194
195static struct list_head *coresight_build_path(struct coresight_device *csdev,
196 struct list_head *path)
197{
198 int i;
199 struct list_head *p;
200 struct coresight_connection *conn;
201
202 if (csdev->id == curr_sink) {
203 list_add_tail(&csdev->path_link, path);
204 return path;
205 }
206
207 for (i = 0; i < csdev->nr_conns; i++) {
208 conn = &csdev->conns[i];
209 p = coresight_build_path(conn->child_dev, path);
210 if (p) {
211 list_add_tail(&csdev->path_link, p);
212 return p;
213 }
214 }
215 return NULL;
216}
217
218static void coresight_release_path(struct list_head *path)
219{
220 struct coresight_device *cd, *temp;
221
222 list_for_each_entry_safe(cd, temp, path, path_link)
223 list_del(&cd->path_link);
224}
225
226static int coresight_enable_path(struct list_head *path, bool incl_source)
227{
228 int ret = 0;
229 struct coresight_device *cd;
230
231 list_for_each_entry(cd, path, path_link) {
232 if (cd == list_first_entry(path, struct coresight_device,
233 path_link)) {
234 ret = coresight_enable_sink(cd);
235 } else if (list_is_last(&cd->path_link, path)) {
236 if (incl_source)
237 ret = coresight_enable_source(cd);
238 } else {
239 ret = coresight_enable_link(cd);
240 }
241 if (ret)
242 goto err;
243 }
244 return 0;
245err:
246 list_for_each_entry_continue_reverse(cd, path, path_link) {
247 if (cd == list_first_entry(path, struct coresight_device,
248 path_link)) {
249 coresight_disable_sink(cd);
250 } else if (list_is_last(&cd->path_link, path)) {
251 if (incl_source)
252 coresight_disable_source(cd);
253 } else {
254 coresight_disable_link(cd);
255 }
256 }
257 return ret;
258}
259
260static void coresight_disable_path(struct list_head *path, bool incl_source)
261{
262 struct coresight_device *cd;
263
264 list_for_each_entry(cd, path, path_link) {
265 if (cd == list_first_entry(path, struct coresight_device,
266 path_link)) {
267 coresight_disable_sink(cd);
268 } else if (list_is_last(&cd->path_link, path)) {
269 if (incl_source)
270 coresight_disable_source(cd);
271 } else {
272 coresight_disable_link(cd);
273 }
274 }
275}
276
277static int coresight_switch_sink(struct coresight_device *csdev)
278{
279 int ret = 0;
280 LIST_HEAD(path);
281 struct coresight_device *cd;
282
283 if (IS_ERR_OR_NULL(csdev))
284 return -EINVAL;
285
286 down(&coresight_mutex);
287 if (csdev->id == curr_sink)
288 goto out;
289
290 list_for_each_entry(cd, &coresight_devs, dev_link) {
291 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
292 coresight_build_path(cd, &path);
293 coresight_disable_path(&path, false);
294 coresight_release_path(&path);
295 }
296 }
297 curr_sink = csdev->id;
298 list_for_each_entry(cd, &coresight_devs, dev_link) {
299 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
300 coresight_build_path(cd, &path);
301 ret = coresight_enable_path(&path, false);
302 coresight_release_path(&path);
303 if (ret)
304 goto err;
305 }
306 }
307out:
308 up(&coresight_mutex);
309 return 0;
310err:
311 list_for_each_entry(cd, &coresight_devs, dev_link) {
312 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
313 coresight_disable_source(cd);
314 }
315 pr_err("coresight: sink switch failed, sources disabled; try again\n");
316 return ret;
317}
318
319int coresight_enable(struct coresight_device *csdev)
320{
321 int ret = 0;
322 LIST_HEAD(path);
323
324 if (IS_ERR_OR_NULL(csdev))
325 return -EINVAL;
326
327 down(&coresight_mutex);
328 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
329 ret = -EINVAL;
330 pr_err("coresight: wrong device type in %s\n", __func__);
331 goto out;
332 }
333 if (csdev->enable)
334 goto out;
335
336 coresight_build_path(csdev, &path);
337 ret = coresight_enable_path(&path, true);
338 coresight_release_path(&path);
339 if (ret)
340 pr_err("coresight: enable failed\n");
341out:
342 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700343 return ret;
344}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700345EXPORT_SYMBOL_GPL(coresight_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700346
Pratik Patel0a7edd32012-06-08 09:31:55 -0700347void coresight_disable(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700348{
Pratik Patel0a7edd32012-06-08 09:31:55 -0700349 LIST_HEAD(path);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700350
Pratik Patel0a7edd32012-06-08 09:31:55 -0700351 if (IS_ERR_OR_NULL(csdev))
352 return;
353
354 down(&coresight_mutex);
355 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
356 pr_err("coresight: wrong device type in %s\n", __func__);
357 goto out;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700358 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700359 if (!csdev->enable)
360 goto out;
361
362 coresight_build_path(csdev, &path);
363 coresight_disable_path(&path, true);
364 coresight_release_path(&path);
365out:
366 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700367}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700368EXPORT_SYMBOL_GPL(coresight_disable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700369
Pratik Patel6fb38342012-06-03 14:51:38 -0700370static ssize_t coresight_show_type(struct device *dev,
371 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700372{
373 return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
374}
375
Pratik Patel6fb38342012-06-03 14:51:38 -0700376static struct device_attribute coresight_dev_attrs[] = {
377 __ATTR(type, S_IRUGO, coresight_show_type, NULL),
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700378 { },
379};
380
Pratik Patel6fb38342012-06-03 14:51:38 -0700381struct bus_type coresight_bus_type = {
382 .name = "coresight",
383 .dev_attrs = coresight_dev_attrs,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700384};
385
Pratik Patel0a7edd32012-06-08 09:31:55 -0700386static ssize_t coresight_show_curr_sink(struct device *dev,
387 struct device_attribute *attr,
388 char *buf)
389{
390 struct coresight_device *csdev = to_coresight_device(dev);
391
392 return scnprintf(buf, PAGE_SIZE, "%u\n",
393 csdev->id == curr_sink ? 1 : 0);
394}
395
396static ssize_t coresight_store_curr_sink(struct device *dev,
397 struct device_attribute *attr,
398 const char *buf, size_t size)
399{
400 int ret = 0;
401 unsigned long val;
402 struct coresight_device *csdev = to_coresight_device(dev);
403
404 if (sscanf(buf, "%lx", &val) != 1)
405 return -EINVAL;
406
407 if (val)
408 ret = coresight_switch_sink(csdev);
409 else
410 ret = -EINVAL;
411
412 if (ret)
413 return ret;
414 return size;
415}
416static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
417 coresight_store_curr_sink);
418
Pratik Patel6fb38342012-06-03 14:51:38 -0700419static ssize_t coresight_show_enable(struct device *dev,
420 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700421{
Pratik Patel6fb38342012-06-03 14:51:38 -0700422 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700423
424 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
425}
426
Pratik Patel6fb38342012-06-03 14:51:38 -0700427static ssize_t coresight_store_enable(struct device *dev,
428 struct device_attribute *attr,
429 const char *buf, size_t size)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700430{
431 int ret = 0;
432 unsigned long val;
Pratik Patel6fb38342012-06-03 14:51:38 -0700433 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700434
435 if (sscanf(buf, "%lx", &val) != 1)
436 return -EINVAL;
437
438 if (val)
Pratik Patel0a7edd32012-06-08 09:31:55 -0700439 ret = coresight_enable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700440 else
Pratik Patel0a7edd32012-06-08 09:31:55 -0700441 coresight_disable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700442
443 if (ret)
444 return ret;
445 return size;
446}
Pratik Patel6fb38342012-06-03 14:51:38 -0700447static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
448 coresight_store_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700449
Pratik Patel0a7edd32012-06-08 09:31:55 -0700450static struct attribute *coresight_attrs_sink[] = {
451 &dev_attr_curr_sink.attr,
452 NULL,
453};
454
455static struct attribute_group coresight_attr_grp_sink = {
456 .attrs = coresight_attrs_sink,
457};
458
459static const struct attribute_group *coresight_attr_grps_sink[] = {
460 &coresight_attr_grp_sink,
461 NULL,
462};
463
464static struct attribute *coresight_attrs_source[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700465 &dev_attr_enable.attr,
466 NULL,
467};
468
Pratik Patel0a7edd32012-06-08 09:31:55 -0700469static struct attribute_group coresight_attr_grp_source = {
470 .attrs = coresight_attrs_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700471};
472
Pratik Patel0a7edd32012-06-08 09:31:55 -0700473static const struct attribute_group *coresight_attr_grps_source[] = {
474 &coresight_attr_grp_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700475 NULL,
476};
477
Pratik Patel0a7edd32012-06-08 09:31:55 -0700478static struct device_type coresight_dev_type[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700479 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700480 .name = "sink",
481 .groups = coresight_attr_grps_sink,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700482 },
483 {
484 .name = "link",
485 },
486 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700487 .name = "linksink",
488 .groups = coresight_attr_grps_sink,
489 },
490 {
491 .name = "source",
492 .groups = coresight_attr_grps_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700493 },
494};
495
Pratik Patel6fb38342012-06-03 14:51:38 -0700496static void coresight_device_release(struct device *dev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700497{
Pratik Patel6fb38342012-06-03 14:51:38 -0700498 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700499 kfree(csdev);
500}
501
Pratik Patel6fb38342012-06-03 14:51:38 -0700502static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700503{
Pratik Patel6fb38342012-06-03 14:51:38 -0700504 struct coresight_connection *conn, *temp;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700505
Pratik Patel6fb38342012-06-03 14:51:38 -0700506 list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700507 if (conn->child_id == csdev->id) {
508 conn->child_dev = csdev;
509 list_del(&conn->link);
510 }
511 }
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700512}
513
Pratik Patel6fb38342012-06-03 14:51:38 -0700514static void coresight_fixup_device_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700515{
516 int i;
Pratik Patel6fb38342012-06-03 14:51:38 -0700517 struct coresight_device *cd;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700518 bool found;
519
520 for (i = 0; i < csdev->nr_conns; i++) {
521 found = false;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700522 list_for_each_entry(cd, &coresight_devs, dev_link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700523 if (csdev->conns[i].child_id == cd->id) {
524 csdev->conns[i].child_dev = cd;
525 found = true;
526 break;
527 }
528 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700529 if (!found)
Pratik Patel6fb38342012-06-03 14:51:38 -0700530 list_add_tail(&csdev->conns[i].link,
531 &coresight_orph_conns);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700532 }
533}
534
Pratik Patel6fb38342012-06-03 14:51:38 -0700535struct coresight_device *coresight_register(struct coresight_desc *desc)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700536{
537 int i;
538 int ret;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700539 int link_subtype;
540 int nr_refcnts;
541 int *refcnts = NULL;
Pratik Patel6fb38342012-06-03 14:51:38 -0700542 struct coresight_device *csdev;
543 struct coresight_connection *conns;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700544
545 csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
546 if (!csdev) {
547 ret = -ENOMEM;
548 goto err_kzalloc_csdev;
549 }
550
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700551 csdev->id = desc->pdata->id;
552
Pratik Patel0a7edd32012-06-08 09:31:55 -0700553 if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
554 desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
555 link_subtype = desc->subtype.link_subtype;
556 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
557 nr_refcnts = desc->pdata->nr_inports;
558 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
559 nr_refcnts = desc->pdata->nr_outports;
560 else
561 nr_refcnts = 1;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700562
Pratik Patel0a7edd32012-06-08 09:31:55 -0700563 refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
564 if (!refcnts) {
565 ret = -ENOMEM;
566 goto err_kzalloc_refcnts;
567 }
568 csdev->refcnt.link_refcnts = refcnts;
569 }
570
571 csdev->nr_conns = desc->pdata->nr_outports;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700572 conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
573 if (!conns) {
574 ret = -ENOMEM;
575 goto err_kzalloc_conns;
576 }
577 for (i = 0; i < csdev->nr_conns; i++) {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700578 conns[i].outport = desc->pdata->outports[i];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700579 conns[i].child_id = desc->pdata->child_ids[i];
580 conns[i].child_port = desc->pdata->child_ports[i];
581 }
582 csdev->conns = conns;
583
Pratik Patel0a7edd32012-06-08 09:31:55 -0700584 csdev->type = desc->type;
585 csdev->subtype = desc->subtype;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700586 csdev->ops = desc->ops;
587 csdev->owner = desc->owner;
588
Pratik Patel6fb38342012-06-03 14:51:38 -0700589 csdev->dev.type = &coresight_dev_type[desc->type];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700590 csdev->dev.groups = desc->groups;
591 csdev->dev.parent = desc->dev;
Pratik Patel6fb38342012-06-03 14:51:38 -0700592 csdev->dev.bus = &coresight_bus_type;
593 csdev->dev.release = coresight_device_release;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700594 dev_set_name(&csdev->dev, "%s", desc->pdata->name);
595
Pratik Patel0a7edd32012-06-08 09:31:55 -0700596 down(&coresight_mutex);
597 if (desc->pdata->default_sink) {
598 if (curr_sink == NO_SINK) {
599 curr_sink = csdev->id;
600 } else {
601 ret = -EINVAL;
602 goto err_default_sink;
603 }
604 }
605
Pratik Patel6fb38342012-06-03 14:51:38 -0700606 coresight_fixup_device_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700607 ret = device_register(&csdev->dev);
608 if (ret)
609 goto err_dev_reg;
Pratik Patel6fb38342012-06-03 14:51:38 -0700610 coresight_fixup_orphan_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700611
Pratik Patel0a7edd32012-06-08 09:31:55 -0700612 list_add_tail(&csdev->dev_link, &coresight_devs);
613 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700614
615 return csdev;
616err_dev_reg:
617 put_device(&csdev->dev);
Pratik Patel0a7edd32012-06-08 09:31:55 -0700618err_default_sink:
619 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700620 kfree(conns);
621err_kzalloc_conns:
Pratik Patel0a7edd32012-06-08 09:31:55 -0700622 kfree(refcnts);
623err_kzalloc_refcnts:
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700624 kfree(csdev);
625err_kzalloc_csdev:
626 return ERR_PTR(ret);
627}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700628EXPORT_SYMBOL_GPL(coresight_register);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700629
Pratik Patel6fb38342012-06-03 14:51:38 -0700630void coresight_unregister(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700631{
632 if (IS_ERR_OR_NULL(csdev))
633 return;
634
635 if (get_device(&csdev->dev)) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700636 device_unregister(&csdev->dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700637 put_device(&csdev->dev);
638 }
639}
Pratik Patel3b0ca882012-06-01 16:54:14 -0700640EXPORT_SYMBOL_GPL(coresight_unregister);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700641
Pratik Patel6fb38342012-06-03 14:51:38 -0700642static int __init coresight_init(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700643{
Pratik Patel6fb38342012-06-03 14:51:38 -0700644 return bus_register(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700645}
Pratik Patel6fb38342012-06-03 14:51:38 -0700646subsys_initcall(coresight_init);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700647
Pratik Patel6fb38342012-06-03 14:51:38 -0700648static void __exit coresight_exit(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700649{
Pratik Patel6fb38342012-06-03 14:51:38 -0700650 bus_unregister(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700651}
Pratik Patel6fb38342012-06-03 14:51:38 -0700652module_exit(coresight_exit);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700653
654MODULE_LICENSE("GPL v2");