1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * THC63LVD1024 LVDS to parallel data DRM bridge driver.
4  *
5  * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
6  */
7 
8 #include <linux/gpio/consumer.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/of_graph.h>
12 #include <linux/platform_device.h>
13 #include <linux/regulator/consumer.h>
14 #include <linux/slab.h>
15 
16 #include <drm/drm_bridge.h>
17 #include <drm/drm_panel.h>
18 
19 enum thc63_ports {
20 	THC63_LVDS_IN0,
21 	THC63_LVDS_IN1,
22 	THC63_RGB_OUT0,
23 	THC63_RGB_OUT1,
24 };
25 
26 struct thc63_dev {
27 	struct device *dev;
28 
29 	struct regulator *vcc;
30 
31 	struct gpio_desc *pdwn;
32 	struct gpio_desc *oe;
33 
34 	struct drm_bridge bridge;
35 	struct drm_bridge *next;
36 };
37 
38 static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
39 {
40 	return container_of(bridge, struct thc63_dev, bridge);
41 }
42 
43 static int thc63_attach(struct drm_bridge *bridge)
44 {
45 	struct thc63_dev *thc63 = to_thc63(bridge);
46 
47 	return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
48 }
49 
50 static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
51 					const struct drm_display_mode *mode)
52 {
53 	/*
54 	 * The THC63LVD1024 clock frequency range is 8 to 135 MHz in single-in
55 	 * mode. Note that the limits are different in dual-in, single-out mode,
56 	 * and will need to be adjusted accordingly.
57 	 */
58 	if (mode->clock < 8000)
59 		return MODE_CLOCK_LOW;
60 
61 	if (mode->clock > 135000)
62 		return MODE_CLOCK_HIGH;
63 
64 	return MODE_OK;
65 }
66 
67 static void thc63_enable(struct drm_bridge *bridge)
68 {
69 	struct thc63_dev *thc63 = to_thc63(bridge);
70 	int ret;
71 
72 	ret = regulator_enable(thc63->vcc);
73 	if (ret) {
74 		dev_err(thc63->dev,
75 			"Failed to enable regulator \"vcc\": %d\n", ret);
76 		return;
77 	}
78 
79 	gpiod_set_value(thc63->pdwn, 0);
80 	gpiod_set_value(thc63->oe, 1);
81 }
82 
83 static void thc63_disable(struct drm_bridge *bridge)
84 {
85 	struct thc63_dev *thc63 = to_thc63(bridge);
86 	int ret;
87 
88 	gpiod_set_value(thc63->oe, 0);
89 	gpiod_set_value(thc63->pdwn, 1);
90 
91 	ret = regulator_disable(thc63->vcc);
92 	if (ret)
93 		dev_err(thc63->dev,
94 			"Failed to disable regulator \"vcc\": %d\n", ret);
95 }
96 
97 static const struct drm_bridge_funcs thc63_bridge_func = {
98 	.attach	= thc63_attach,
99 	.mode_valid = thc63_mode_valid,
100 	.enable = thc63_enable,
101 	.disable = thc63_disable,
102 };
103 
104 static int thc63_parse_dt(struct thc63_dev *thc63)
105 {
106 	struct device_node *thc63_out;
107 	struct device_node *remote;
108 
109 	thc63_out = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
110 						  THC63_RGB_OUT0, -1);
111 	if (!thc63_out) {
112 		dev_err(thc63->dev, "Missing endpoint in port@%u\n",
113 			THC63_RGB_OUT0);
114 		return -ENODEV;
115 	}
116 
117 	remote = of_graph_get_remote_port_parent(thc63_out);
118 	of_node_put(thc63_out);
119 	if (!remote) {
120 		dev_err(thc63->dev, "Endpoint in port@%u unconnected\n",
121 			THC63_RGB_OUT0);
122 		return -ENODEV;
123 	}
124 
125 	if (!of_device_is_available(remote)) {
126 		dev_err(thc63->dev, "port@%u remote endpoint is disabled\n",
127 			THC63_RGB_OUT0);
128 		of_node_put(remote);
129 		return -ENODEV;
130 	}
131 
132 	thc63->next = of_drm_find_bridge(remote);
133 	of_node_put(remote);
134 	if (!thc63->next)
135 		return -EPROBE_DEFER;
136 
137 	return 0;
138 }
139 
140 static int thc63_gpio_init(struct thc63_dev *thc63)
141 {
142 	thc63->oe = devm_gpiod_get_optional(thc63->dev, "oe", GPIOD_OUT_LOW);
143 	if (IS_ERR(thc63->oe)) {
144 		dev_err(thc63->dev, "Unable to get \"oe-gpios\": %ld\n",
145 			PTR_ERR(thc63->oe));
146 		return PTR_ERR(thc63->oe);
147 	}
148 
149 	thc63->pdwn = devm_gpiod_get_optional(thc63->dev, "powerdown",
150 					      GPIOD_OUT_HIGH);
151 	if (IS_ERR(thc63->pdwn)) {
152 		dev_err(thc63->dev, "Unable to get \"powerdown-gpios\": %ld\n",
153 			PTR_ERR(thc63->pdwn));
154 		return PTR_ERR(thc63->pdwn);
155 	}
156 
157 	return 0;
158 }
159 
160 static int thc63_probe(struct platform_device *pdev)
161 {
162 	struct thc63_dev *thc63;
163 	int ret;
164 
165 	thc63 = devm_kzalloc(&pdev->dev, sizeof(*thc63), GFP_KERNEL);
166 	if (!thc63)
167 		return -ENOMEM;
168 
169 	thc63->dev = &pdev->dev;
170 	platform_set_drvdata(pdev, thc63);
171 
172 	thc63->vcc = devm_regulator_get_optional(thc63->dev, "vcc");
173 	if (IS_ERR(thc63->vcc)) {
174 		if (PTR_ERR(thc63->vcc) == -EPROBE_DEFER)
175 			return -EPROBE_DEFER;
176 
177 		dev_err(thc63->dev, "Unable to get \"vcc\" supply: %ld\n",
178 			PTR_ERR(thc63->vcc));
179 		return PTR_ERR(thc63->vcc);
180 	}
181 
182 	ret = thc63_gpio_init(thc63);
183 	if (ret)
184 		return ret;
185 
186 	ret = thc63_parse_dt(thc63);
187 	if (ret)
188 		return ret;
189 
190 	thc63->bridge.driver_private = thc63;
191 	thc63->bridge.of_node = pdev->dev.of_node;
192 	thc63->bridge.funcs = &thc63_bridge_func;
193 
194 	drm_bridge_add(&thc63->bridge);
195 
196 	return 0;
197 }
198 
199 static int thc63_remove(struct platform_device *pdev)
200 {
201 	struct thc63_dev *thc63 = platform_get_drvdata(pdev);
202 
203 	drm_bridge_remove(&thc63->bridge);
204 
205 	return 0;
206 }
207 
208 static const struct of_device_id thc63_match[] = {
209 	{ .compatible = "thine,thc63lvd1024", },
210 	{ },
211 };
212 MODULE_DEVICE_TABLE(of, thc63_match);
213 
214 static struct platform_driver thc63_driver = {
215 	.probe	= thc63_probe,
216 	.remove	= thc63_remove,
217 	.driver	= {
218 		.name		= "thc63lvd1024",
219 		.of_match_table	= thc63_match,
220 	},
221 };
222 module_platform_driver(thc63_driver);
223 
224 MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
225 MODULE_DESCRIPTION("Thine THC63LVD1024 LVDS decoder DRM bridge driver");
226 MODULE_LICENSE("GPL v2");
227