1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 Texas Instruments
4 * Author: Jyri Sarha <jsarha@ti.com>
7 #include <linux/gpio/consumer.h>
9 #include <linux/module.h>
10 #include <linux/of_graph.h>
11 #include <linux/platform_device.h>
12 #include <linux/workqueue.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_bridge.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_print.h>
18 #include <drm/drm_probe_helper.h>
20 #define HOTPLUG_DEBOUNCE_MS 1100
23 struct drm_bridge bridge
;
24 struct drm_connector connector
;
27 struct delayed_work hpd_work
;
28 struct gpio_desc
*powerdown
;
30 struct drm_bridge_timings timings
;
31 struct drm_bridge
*next_bridge
;
36 static inline struct tfp410
*
37 drm_bridge_to_tfp410(struct drm_bridge
*bridge
)
39 return container_of(bridge
, struct tfp410
, bridge
);
42 static inline struct tfp410
*
43 drm_connector_to_tfp410(struct drm_connector
*connector
)
45 return container_of(connector
, struct tfp410
, connector
);
48 static int tfp410_get_modes(struct drm_connector
*connector
)
50 struct tfp410
*dvi
= drm_connector_to_tfp410(connector
);
54 if (dvi
->next_bridge
->ops
& DRM_BRIDGE_OP_EDID
) {
55 edid
= drm_bridge_get_edid(dvi
->next_bridge
, connector
);
57 DRM_INFO("EDID read failed. Fallback to standard modes\n");
64 * No EDID, fallback on the XGA standard modes and prefer a mode
65 * pretty much anything can handle.
67 ret
= drm_add_modes_noedid(connector
, 1920, 1200);
68 drm_set_preferred_mode(connector
, 1024, 768);
72 drm_connector_update_edid_property(connector
, edid
);
74 ret
= drm_add_edid_modes(connector
, edid
);
81 static const struct drm_connector_helper_funcs tfp410_con_helper_funcs
= {
82 .get_modes
= tfp410_get_modes
,
85 static enum drm_connector_status
86 tfp410_connector_detect(struct drm_connector
*connector
, bool force
)
88 struct tfp410
*dvi
= drm_connector_to_tfp410(connector
);
90 return drm_bridge_detect(dvi
->next_bridge
);
93 static const struct drm_connector_funcs tfp410_con_funcs
= {
94 .detect
= tfp410_connector_detect
,
95 .fill_modes
= drm_helper_probe_single_connector_modes
,
96 .destroy
= drm_connector_cleanup
,
97 .reset
= drm_atomic_helper_connector_reset
,
98 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
99 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
102 static void tfp410_hpd_work_func(struct work_struct
*work
)
106 dvi
= container_of(work
, struct tfp410
, hpd_work
.work
);
109 drm_helper_hpd_irq_event(dvi
->bridge
.dev
);
112 static void tfp410_hpd_callback(void *arg
, enum drm_connector_status status
)
114 struct tfp410
*dvi
= arg
;
116 mod_delayed_work(system_wq
, &dvi
->hpd_work
,
117 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS
));
120 static int tfp410_attach(struct drm_bridge
*bridge
,
121 enum drm_bridge_attach_flags flags
)
123 struct tfp410
*dvi
= drm_bridge_to_tfp410(bridge
);
126 ret
= drm_bridge_attach(bridge
->encoder
, dvi
->next_bridge
, bridge
,
127 DRM_BRIDGE_ATTACH_NO_CONNECTOR
);
131 if (flags
& DRM_BRIDGE_ATTACH_NO_CONNECTOR
)
134 if (!bridge
->encoder
) {
135 dev_err(dvi
->dev
, "Missing encoder\n");
139 if (dvi
->next_bridge
->ops
& DRM_BRIDGE_OP_DETECT
)
140 dvi
->connector
.polled
= DRM_CONNECTOR_POLL_HPD
;
142 dvi
->connector
.polled
= DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT
;
144 if (dvi
->next_bridge
->ops
& DRM_BRIDGE_OP_HPD
) {
145 INIT_DELAYED_WORK(&dvi
->hpd_work
, tfp410_hpd_work_func
);
146 drm_bridge_hpd_enable(dvi
->next_bridge
, tfp410_hpd_callback
,
150 drm_connector_helper_add(&dvi
->connector
,
151 &tfp410_con_helper_funcs
);
152 ret
= drm_connector_init_with_ddc(bridge
->dev
, &dvi
->connector
,
154 dvi
->next_bridge
->type
,
155 dvi
->next_bridge
->ddc
);
157 dev_err(dvi
->dev
, "drm_connector_init_with_ddc() failed: %d\n",
162 drm_display_info_set_bus_formats(&dvi
->connector
.display_info
,
163 &dvi
->bus_format
, 1);
165 drm_connector_attach_encoder(&dvi
->connector
, bridge
->encoder
);
170 static void tfp410_detach(struct drm_bridge
*bridge
)
172 struct tfp410
*dvi
= drm_bridge_to_tfp410(bridge
);
174 if (dvi
->connector
.dev
&& dvi
->next_bridge
->ops
& DRM_BRIDGE_OP_HPD
) {
175 drm_bridge_hpd_disable(dvi
->next_bridge
);
176 cancel_delayed_work_sync(&dvi
->hpd_work
);
180 static void tfp410_enable(struct drm_bridge
*bridge
)
182 struct tfp410
*dvi
= drm_bridge_to_tfp410(bridge
);
184 gpiod_set_value_cansleep(dvi
->powerdown
, 0);
187 static void tfp410_disable(struct drm_bridge
*bridge
)
189 struct tfp410
*dvi
= drm_bridge_to_tfp410(bridge
);
191 gpiod_set_value_cansleep(dvi
->powerdown
, 1);
194 static enum drm_mode_status
tfp410_mode_valid(struct drm_bridge
*bridge
,
195 const struct drm_display_info
*info
,
196 const struct drm_display_mode
*mode
)
198 if (mode
->clock
< 25000)
199 return MODE_CLOCK_LOW
;
201 if (mode
->clock
> 165000)
202 return MODE_CLOCK_HIGH
;
207 static const struct drm_bridge_funcs tfp410_bridge_funcs
= {
208 .attach
= tfp410_attach
,
209 .detach
= tfp410_detach
,
210 .enable
= tfp410_enable
,
211 .disable
= tfp410_disable
,
212 .mode_valid
= tfp410_mode_valid
,
215 static const struct drm_bridge_timings tfp410_default_timings
= {
216 .input_bus_flags
= DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
217 | DRM_BUS_FLAG_DE_HIGH
,
218 .setup_time_ps
= 1200,
219 .hold_time_ps
= 1300,
222 static int tfp410_parse_timings(struct tfp410
*dvi
, bool i2c
)
224 struct drm_bridge_timings
*timings
= &dvi
->timings
;
225 struct device_node
*ep
;
230 /* Start with defaults. */
231 *timings
= tfp410_default_timings
;
235 * In I2C mode timings are configured through the I2C interface.
236 * As the driver doesn't support I2C configuration yet, we just
237 * go with the defaults (BSEL=1, DSEL=1, DKEN=0, EDGE=1).
242 * In non-I2C mode, timings are configured through the BSEL, DSEL, DKEN
243 * and EDGE pins. They are specified in DT through endpoint properties
244 * and vendor-specific properties.
246 ep
= of_graph_get_endpoint_by_regs(dvi
->dev
->of_node
, 0, 0);
250 /* Get the sampling edge from the endpoint. */
251 of_property_read_u32(ep
, "pclk-sample", &pclk_sample
);
252 of_property_read_u32(ep
, "bus-width", &bus_width
);
255 timings
->input_bus_flags
= DRM_BUS_FLAG_DE_HIGH
;
257 switch (pclk_sample
) {
259 timings
->input_bus_flags
|= DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE
260 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE
;
263 timings
->input_bus_flags
|= DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
264 | DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE
;
272 dvi
->bus_format
= MEDIA_BUS_FMT_RGB888_2X12_LE
;
275 dvi
->bus_format
= MEDIA_BUS_FMT_RGB888_1X24
;
281 /* Get the setup and hold time from vendor-specific properties. */
282 of_property_read_u32(dvi
->dev
->of_node
, "ti,deskew", &deskew
);
286 timings
->setup_time_ps
= 1200 - 350 * ((s32
)deskew
- 4);
287 timings
->hold_time_ps
= max(0, 1300 + 350 * ((s32
)deskew
- 4));
292 static int tfp410_init(struct device
*dev
, bool i2c
)
294 struct device_node
*node
;
299 dev_err(dev
, "device-tree data is missing\n");
303 dvi
= devm_kzalloc(dev
, sizeof(*dvi
), GFP_KERNEL
);
308 dev_set_drvdata(dev
, dvi
);
310 dvi
->bridge
.funcs
= &tfp410_bridge_funcs
;
311 dvi
->bridge
.of_node
= dev
->of_node
;
312 dvi
->bridge
.timings
= &dvi
->timings
;
313 dvi
->bridge
.type
= DRM_MODE_CONNECTOR_DVID
;
315 ret
= tfp410_parse_timings(dvi
, i2c
);
319 /* Get the next bridge, connected to port@1. */
320 node
= of_graph_get_remote_node(dev
->of_node
, 1, -1);
324 dvi
->next_bridge
= of_drm_find_bridge(node
);
327 if (!dvi
->next_bridge
)
328 return -EPROBE_DEFER
;
330 /* Get the powerdown GPIO. */
331 dvi
->powerdown
= devm_gpiod_get_optional(dev
, "powerdown",
333 if (IS_ERR(dvi
->powerdown
)) {
334 dev_err(dev
, "failed to parse powerdown gpio\n");
335 return PTR_ERR(dvi
->powerdown
);
338 /* Register the DRM bridge. */
339 drm_bridge_add(&dvi
->bridge
);
344 static int tfp410_fini(struct device
*dev
)
346 struct tfp410
*dvi
= dev_get_drvdata(dev
);
348 drm_bridge_remove(&dvi
->bridge
);
353 static int tfp410_probe(struct platform_device
*pdev
)
355 return tfp410_init(&pdev
->dev
, false);
358 static int tfp410_remove(struct platform_device
*pdev
)
360 return tfp410_fini(&pdev
->dev
);
363 static const struct of_device_id tfp410_match
[] = {
364 { .compatible
= "ti,tfp410" },
367 MODULE_DEVICE_TABLE(of
, tfp410_match
);
369 static struct platform_driver tfp410_platform_driver
= {
370 .probe
= tfp410_probe
,
371 .remove
= tfp410_remove
,
373 .name
= "tfp410-bridge",
374 .of_match_table
= tfp410_match
,
378 #if IS_ENABLED(CONFIG_I2C)
379 /* There is currently no i2c functionality. */
380 static int tfp410_i2c_probe(struct i2c_client
*client
,
381 const struct i2c_device_id
*id
)
385 if (!client
->dev
.of_node
||
386 of_property_read_u32(client
->dev
.of_node
, "reg", ®
)) {
387 dev_err(&client
->dev
,
388 "Can't get i2c reg property from device-tree\n");
392 return tfp410_init(&client
->dev
, true);
395 static int tfp410_i2c_remove(struct i2c_client
*client
)
397 return tfp410_fini(&client
->dev
);
400 static const struct i2c_device_id tfp410_i2c_ids
[] = {
404 MODULE_DEVICE_TABLE(i2c
, tfp410_i2c_ids
);
406 static struct i2c_driver tfp410_i2c_driver
= {
409 .of_match_table
= of_match_ptr(tfp410_match
),
411 .id_table
= tfp410_i2c_ids
,
412 .probe
= tfp410_i2c_probe
,
413 .remove
= tfp410_i2c_remove
,
415 #endif /* IS_ENABLED(CONFIG_I2C) */
420 } tfp410_registered_driver
;
422 static int __init
tfp410_module_init(void)
426 #if IS_ENABLED(CONFIG_I2C)
427 ret
= i2c_add_driver(&tfp410_i2c_driver
);
429 pr_err("%s: registering i2c driver failed: %d",
432 tfp410_registered_driver
.i2c
= 1;
435 ret
= platform_driver_register(&tfp410_platform_driver
);
437 pr_err("%s: registering platform driver failed: %d",
440 tfp410_registered_driver
.platform
= 1;
442 if (tfp410_registered_driver
.i2c
||
443 tfp410_registered_driver
.platform
)
448 module_init(tfp410_module_init
);
450 static void __exit
tfp410_module_exit(void)
452 #if IS_ENABLED(CONFIG_I2C)
453 if (tfp410_registered_driver
.i2c
)
454 i2c_del_driver(&tfp410_i2c_driver
);
456 if (tfp410_registered_driver
.platform
)
457 platform_driver_unregister(&tfp410_platform_driver
);
459 module_exit(tfp410_module_exit
);
461 MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
462 MODULE_DESCRIPTION("TI TFP410 DVI bridge driver");
463 MODULE_LICENSE("GPL");