Commit | Line | Data |
---|---|---|
99fd133f GL |
1 | /* |
2 | * V4L2 OF binding parsing library | |
3 | * | |
4 | * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. | |
c6e8d96d | 5 | * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> |
99fd133f GL |
6 | * |
7 | * Copyright (C) 2012 Renesas Electronics Corp. | |
8 | * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of version 2 of the GNU General Public License as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/of.h> | |
17 | #include <linux/string.h> | |
18 | #include <linux/types.h> | |
19 | ||
20 | #include <media/v4l2-of.h> | |
21 | ||
22 | static void v4l2_of_parse_csi_bus(const struct device_node *node, | |
23 | struct v4l2_of_endpoint *endpoint) | |
24 | { | |
25 | struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; | |
26 | u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; | |
27 | struct property *prop; | |
28 | bool have_clk_lane = false; | |
29 | unsigned int flags = 0; | |
30 | u32 v; | |
31 | ||
32 | prop = of_find_property(node, "data-lanes", NULL); | |
33 | if (prop) { | |
34 | const __be32 *lane = NULL; | |
35 | int i; | |
36 | ||
37 | for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { | |
38 | lane = of_prop_next_u32(prop, lane, &data_lanes[i]); | |
39 | if (!lane) | |
40 | break; | |
41 | } | |
42 | bus->num_data_lanes = i; | |
43 | while (i--) | |
44 | bus->data_lanes[i] = data_lanes[i]; | |
45 | } | |
46 | ||
47 | if (!of_property_read_u32(node, "clock-lanes", &v)) { | |
48 | bus->clock_lane = v; | |
49 | have_clk_lane = true; | |
50 | } | |
51 | ||
52 | if (of_get_property(node, "clock-noncontinuous", &v)) | |
53 | flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; | |
54 | else if (have_clk_lane || bus->num_data_lanes > 0) | |
55 | flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | |
56 | ||
57 | bus->flags = flags; | |
58 | endpoint->bus_type = V4L2_MBUS_CSI2; | |
59 | } | |
60 | ||
61 | static void v4l2_of_parse_parallel_bus(const struct device_node *node, | |
62 | struct v4l2_of_endpoint *endpoint) | |
63 | { | |
64 | struct v4l2_of_bus_parallel *bus = &endpoint->bus.parallel; | |
65 | unsigned int flags = 0; | |
66 | u32 v; | |
67 | ||
68 | if (!of_property_read_u32(node, "hsync-active", &v)) | |
69 | flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH : | |
70 | V4L2_MBUS_HSYNC_ACTIVE_LOW; | |
71 | ||
72 | if (!of_property_read_u32(node, "vsync-active", &v)) | |
73 | flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH : | |
74 | V4L2_MBUS_VSYNC_ACTIVE_LOW; | |
75 | ||
76 | if (!of_property_read_u32(node, "pclk-sample", &v)) | |
77 | flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : | |
78 | V4L2_MBUS_PCLK_SAMPLE_FALLING; | |
79 | ||
80 | if (!of_property_read_u32(node, "field-even-active", &v)) | |
81 | flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH : | |
82 | V4L2_MBUS_FIELD_EVEN_LOW; | |
83 | if (flags) | |
84 | endpoint->bus_type = V4L2_MBUS_PARALLEL; | |
85 | else | |
86 | endpoint->bus_type = V4L2_MBUS_BT656; | |
87 | ||
88 | if (!of_property_read_u32(node, "data-active", &v)) | |
89 | flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH : | |
90 | V4L2_MBUS_DATA_ACTIVE_LOW; | |
91 | ||
92 | if (of_get_property(node, "slave-mode", &v)) | |
93 | flags |= V4L2_MBUS_SLAVE; | |
94 | else | |
95 | flags |= V4L2_MBUS_MASTER; | |
96 | ||
97 | if (!of_property_read_u32(node, "bus-width", &v)) | |
98 | bus->bus_width = v; | |
99 | ||
100 | if (!of_property_read_u32(node, "data-shift", &v)) | |
101 | bus->data_shift = v; | |
102 | ||
d1d70aa6 LP |
103 | if (!of_property_read_u32(node, "sync-on-green-active", &v)) |
104 | flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH : | |
105 | V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW; | |
106 | ||
99fd133f GL |
107 | bus->flags = flags; |
108 | ||
109 | } | |
99fd133f GL |
110 | |
111 | /** | |
112 | * v4l2_of_parse_endpoint() - parse all endpoint node properties | |
113 | * @node: pointer to endpoint device_node | |
114 | * @endpoint: pointer to the V4L2 OF endpoint data structure | |
115 | * | |
116 | * All properties are optional. If none are found, we don't set any flags. | |
117 | * This means the port has a static configuration and no properties have | |
118 | * to be specified explicitly. | |
119 | * If any properties that identify the bus as parallel are found and | |
120 | * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise | |
121 | * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the | |
122 | * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. | |
123 | * The caller should hold a reference to @node. | |
9ff889b6 LP |
124 | * |
125 | * Return: 0. | |
99fd133f | 126 | */ |
9ff889b6 LP |
127 | int v4l2_of_parse_endpoint(const struct device_node *node, |
128 | struct v4l2_of_endpoint *endpoint) | |
99fd133f | 129 | { |
f2a575f6 PZ |
130 | of_graph_parse_endpoint(node, &endpoint->base); |
131 | endpoint->bus_type = 0; | |
132 | memset(&endpoint->bus, 0, sizeof(endpoint->bus)); | |
99fd133f GL |
133 | |
134 | v4l2_of_parse_csi_bus(node, endpoint); | |
135 | /* | |
136 | * Parse the parallel video bus properties only if none | |
137 | * of the MIPI CSI-2 specific properties were found. | |
138 | */ | |
139 | if (endpoint->bus.mipi_csi2.flags == 0) | |
140 | v4l2_of_parse_parallel_bus(node, endpoint); | |
141 | ||
9ff889b6 | 142 | return 0; |
99fd133f GL |
143 | } |
144 | EXPORT_SYMBOL(v4l2_of_parse_endpoint); |