1 /*
2  * Copyright (C) 2013 Texas Instruments
3  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  */
14 
15 #include <linux/device.h>
16 #include <linux/err.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/seq_file.h>
20 
21 #include <video/omapdss.h>
22 
23 #include "dss.h"
24 
25 struct device_node *
omapdss_of_get_next_port(const struct device_node * parent,struct device_node * prev)26 omapdss_of_get_next_port(const struct device_node *parent,
27 			 struct device_node *prev)
28 {
29 	struct device_node *port = NULL;
30 
31 	if (!parent)
32 		return NULL;
33 
34 	if (!prev) {
35 		struct device_node *ports;
36 		/*
37 		 * It's the first call, we have to find a port subnode
38 		 * within this node or within an optional 'ports' node.
39 		 */
40 		ports = of_get_child_by_name(parent, "ports");
41 		if (ports)
42 			parent = ports;
43 
44 		port = of_get_child_by_name(parent, "port");
45 
46 		/* release the 'ports' node */
47 		of_node_put(ports);
48 	} else {
49 		struct device_node *ports;
50 
51 		ports = of_get_parent(prev);
52 		if (!ports)
53 			return NULL;
54 
55 		do {
56 			port = of_get_next_child(ports, prev);
57 			if (!port) {
58 				of_node_put(ports);
59 				return NULL;
60 			}
61 			prev = port;
62 		} while (of_node_cmp(port->name, "port") != 0);
63 	}
64 
65 	return port;
66 }
67 EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
68 
69 struct device_node *
omapdss_of_get_next_endpoint(const struct device_node * parent,struct device_node * prev)70 omapdss_of_get_next_endpoint(const struct device_node *parent,
71 			     struct device_node *prev)
72 {
73 	struct device_node *ep = NULL;
74 
75 	if (!parent)
76 		return NULL;
77 
78 	do {
79 		ep = of_get_next_child(parent, prev);
80 		if (!ep)
81 			return NULL;
82 		prev = ep;
83 	} while (of_node_cmp(ep->name, "endpoint") != 0);
84 
85 	return ep;
86 }
87 EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
88 
dss_of_port_get_parent_device(struct device_node * port)89 struct device_node *dss_of_port_get_parent_device(struct device_node *port)
90 {
91 	struct device_node *np;
92 	int i;
93 
94 	if (!port)
95 		return NULL;
96 
97 	np = of_get_next_parent(port);
98 
99 	for (i = 0; i < 2 && np; ++i) {
100 		struct property *prop;
101 
102 		prop = of_find_property(np, "compatible", NULL);
103 
104 		if (prop)
105 			return np;
106 
107 		np = of_get_next_parent(np);
108 	}
109 
110 	return NULL;
111 }
112 
dss_of_port_get_port_number(struct device_node * port)113 u32 dss_of_port_get_port_number(struct device_node *port)
114 {
115 	int r;
116 	u32 reg;
117 
118 	r = of_property_read_u32(port, "reg", &reg);
119 	if (r)
120 		reg = 0;
121 
122 	return reg;
123 }
124 
omapdss_of_get_remote_port(const struct device_node * node)125 static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
126 {
127 	struct device_node *np;
128 
129 	np = of_parse_phandle(node, "remote-endpoint", 0);
130 	if (!np)
131 		return NULL;
132 
133 	np = of_get_next_parent(np);
134 
135 	return np;
136 }
137 
138 struct device_node *
omapdss_of_get_first_endpoint(const struct device_node * parent)139 omapdss_of_get_first_endpoint(const struct device_node *parent)
140 {
141 	struct device_node *port, *ep;
142 
143 	port = omapdss_of_get_next_port(parent, NULL);
144 
145 	if (!port)
146 		return NULL;
147 
148 	ep = omapdss_of_get_next_endpoint(port, NULL);
149 
150 	of_node_put(port);
151 
152 	return ep;
153 }
154 EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
155 
156 struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node * node)157 omapdss_of_find_source_for_first_ep(struct device_node *node)
158 {
159 	struct device_node *ep;
160 	struct device_node *src_port;
161 	struct omap_dss_device *src;
162 
163 	ep = omapdss_of_get_first_endpoint(node);
164 	if (!ep)
165 		return ERR_PTR(-EINVAL);
166 
167 	src_port = omapdss_of_get_remote_port(ep);
168 	if (!src_port) {
169 		of_node_put(ep);
170 		return ERR_PTR(-EINVAL);
171 	}
172 
173 	of_node_put(ep);
174 
175 	src = omap_dss_find_output_by_port_node(src_port);
176 
177 	of_node_put(src_port);
178 
179 	return src ? src : ERR_PTR(-EPROBE_DEFER);
180 }
181 EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
182