1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2019 Renesas Electronics Corporation
4  * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
5  */
6 
7 #include <linux/gpio/consumer.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/of_device.h>
11 #include <linux/of_graph.h>
12 #include <linux/platform_device.h>
13 #include <linux/regulator/consumer.h>
14 
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_bridge.h>
17 #include <drm/drm_panel.h>
18 
19 struct lvds_codec {
20 	struct device *dev;
21 	struct drm_bridge bridge;
22 	struct drm_bridge *panel_bridge;
23 	struct regulator *vcc;
24 	struct gpio_desc *powerdown_gpio;
25 	u32 connector_type;
26 	unsigned int bus_format;
27 };
28 
29 static inline struct lvds_codec *to_lvds_codec(struct drm_bridge *bridge)
30 {
31 	return container_of(bridge, struct lvds_codec, bridge);
32 }
33 
34 static int lvds_codec_attach(struct drm_bridge *bridge,
35 			     enum drm_bridge_attach_flags flags)
36 {
37 	struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
38 
39 	return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge,
40 				 bridge, flags);
41 }
42 
43 static void lvds_codec_enable(struct drm_bridge *bridge)
44 {
45 	struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
46 	int ret;
47 
48 	ret = regulator_enable(lvds_codec->vcc);
49 	if (ret) {
50 		dev_err(lvds_codec->dev,
51 			"Failed to enable regulator \"vcc\": %d\n", ret);
52 		return;
53 	}
54 
55 	if (lvds_codec->powerdown_gpio)
56 		gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0);
57 }
58 
59 static void lvds_codec_disable(struct drm_bridge *bridge)
60 {
61 	struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
62 	int ret;
63 
64 	if (lvds_codec->powerdown_gpio)
65 		gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
66 
67 	ret = regulator_disable(lvds_codec->vcc);
68 	if (ret)
69 		dev_err(lvds_codec->dev,
70 			"Failed to disable regulator \"vcc\": %d\n", ret);
71 }
72 
73 static const struct drm_bridge_funcs funcs = {
74 	.attach = lvds_codec_attach,
75 	.enable = lvds_codec_enable,
76 	.disable = lvds_codec_disable,
77 };
78 
79 #define MAX_INPUT_SEL_FORMATS 1
80 static u32 *
81 lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
82 				     struct drm_bridge_state *bridge_state,
83 				     struct drm_crtc_state *crtc_state,
84 				     struct drm_connector_state *conn_state,
85 				     u32 output_fmt,
86 				     unsigned int *num_input_fmts)
87 {
88 	struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
89 	u32 *input_fmts;
90 
91 	*num_input_fmts = 0;
92 
93 	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
94 			     GFP_KERNEL);
95 	if (!input_fmts)
96 		return NULL;
97 
98 	input_fmts[0] = lvds_codec->bus_format;
99 	*num_input_fmts = MAX_INPUT_SEL_FORMATS;
100 
101 	return input_fmts;
102 }
103 
104 static const struct drm_bridge_funcs funcs_decoder = {
105 	.attach = lvds_codec_attach,
106 	.enable = lvds_codec_enable,
107 	.disable = lvds_codec_disable,
108 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
109 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
110 	.atomic_reset = drm_atomic_helper_bridge_reset,
111 	.atomic_get_input_bus_fmts = lvds_codec_atomic_get_input_bus_fmts,
112 };
113 
114 static int lvds_codec_probe(struct platform_device *pdev)
115 {
116 	struct device *dev = &pdev->dev;
117 	struct device_node *panel_node;
118 	struct device_node *bus_node;
119 	struct drm_panel *panel;
120 	struct lvds_codec *lvds_codec;
121 	const char *mapping;
122 	int ret;
123 
124 	lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
125 	if (!lvds_codec)
126 		return -ENOMEM;
127 
128 	lvds_codec->dev = &pdev->dev;
129 	lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
130 
131 	lvds_codec->vcc = devm_regulator_get(lvds_codec->dev, "power");
132 	if (IS_ERR(lvds_codec->vcc))
133 		return dev_err_probe(dev, PTR_ERR(lvds_codec->vcc),
134 				     "Unable to get \"vcc\" supply\n");
135 
136 	lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
137 							     GPIOD_OUT_HIGH);
138 	if (IS_ERR(lvds_codec->powerdown_gpio))
139 		return dev_err_probe(dev, PTR_ERR(lvds_codec->powerdown_gpio),
140 				     "powerdown GPIO failure\n");
141 
142 	/* Locate the panel DT node. */
143 	panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
144 	if (!panel_node) {
145 		dev_dbg(dev, "panel DT node not found\n");
146 		return -ENXIO;
147 	}
148 
149 	panel = of_drm_find_panel(panel_node);
150 	of_node_put(panel_node);
151 	if (IS_ERR(panel)) {
152 		dev_dbg(dev, "panel not found, deferring probe\n");
153 		return PTR_ERR(panel);
154 	}
155 
156 	lvds_codec->panel_bridge =
157 		devm_drm_panel_bridge_add_typed(dev, panel,
158 						lvds_codec->connector_type);
159 	if (IS_ERR(lvds_codec->panel_bridge))
160 		return PTR_ERR(lvds_codec->panel_bridge);
161 
162 	lvds_codec->bridge.funcs = &funcs;
163 
164 	/*
165 	 * Decoder input LVDS format is a property of the decoder chip or even
166 	 * its strapping. Handle data-mapping the same way lvds-panel does. In
167 	 * case data-mapping is not present, do nothing, since there are still
168 	 * legacy bindings which do not specify this property.
169 	 */
170 	if (lvds_codec->connector_type != DRM_MODE_CONNECTOR_LVDS) {
171 		bus_node = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
172 		if (!bus_node) {
173 			dev_dbg(dev, "bus DT node not found\n");
174 			return -ENXIO;
175 		}
176 
177 		ret = of_property_read_string(bus_node, "data-mapping",
178 					      &mapping);
179 		of_node_put(bus_node);
180 		if (ret < 0) {
181 			dev_warn(dev, "missing 'data-mapping' DT property\n");
182 		} else {
183 			if (!strcmp(mapping, "jeida-18")) {
184 				lvds_codec->bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG;
185 			} else if (!strcmp(mapping, "jeida-24")) {
186 				lvds_codec->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
187 			} else if (!strcmp(mapping, "vesa-24")) {
188 				lvds_codec->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
189 			} else {
190 				dev_err(dev, "invalid 'data-mapping' DT property\n");
191 				return -EINVAL;
192 			}
193 			lvds_codec->bridge.funcs = &funcs_decoder;
194 		}
195 	}
196 
197 	/*
198 	 * The panel_bridge bridge is attached to the panel's of_node,
199 	 * but we need a bridge attached to our of_node for our user
200 	 * to look up.
201 	 */
202 	lvds_codec->bridge.of_node = dev->of_node;
203 	drm_bridge_add(&lvds_codec->bridge);
204 
205 	platform_set_drvdata(pdev, lvds_codec);
206 
207 	return 0;
208 }
209 
210 static int lvds_codec_remove(struct platform_device *pdev)
211 {
212 	struct lvds_codec *lvds_codec = platform_get_drvdata(pdev);
213 
214 	drm_bridge_remove(&lvds_codec->bridge);
215 
216 	return 0;
217 }
218 
219 static const struct of_device_id lvds_codec_match[] = {
220 	{
221 		.compatible = "lvds-decoder",
222 		.data = (void *)DRM_MODE_CONNECTOR_DPI,
223 	},
224 	{
225 		.compatible = "lvds-encoder",
226 		.data = (void *)DRM_MODE_CONNECTOR_LVDS,
227 	},
228 	{
229 		.compatible = "thine,thc63lvdm83d",
230 		.data = (void *)DRM_MODE_CONNECTOR_LVDS,
231 	},
232 	{},
233 };
234 MODULE_DEVICE_TABLE(of, lvds_codec_match);
235 
236 static struct platform_driver lvds_codec_driver = {
237 	.probe	= lvds_codec_probe,
238 	.remove	= lvds_codec_remove,
239 	.driver		= {
240 		.name		= "lvds-codec",
241 		.of_match_table	= lvds_codec_match,
242 	},
243 };
244 module_platform_driver(lvds_codec_driver);
245 
246 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
247 MODULE_DESCRIPTION("LVDS encoders and decoders");
248 MODULE_LICENSE("GPL");
249