1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2024 Freebox SAS
4  */
5 
6 #include <linux/gpio/consumer.h>
7 #include <linux/i2c.h>
8 
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_bridge.h>
11 
12 struct tdp158 {
13 	struct drm_bridge bridge;
14 	struct drm_bridge *next;
15 	struct gpio_desc *enable; // Operation Enable - pin 36
16 	struct regulator *vcc; // 3.3V
17 	struct regulator *vdd; // 1.1V
18 	struct device *dev;
19 };
20 
tdp158_enable(struct drm_bridge * bridge,struct drm_atomic_state * state)21 static void tdp158_enable(struct drm_bridge *bridge,
22 			  struct drm_atomic_state *state)
23 {
24 	int err;
25 	struct tdp158 *tdp158 = bridge->driver_private;
26 
27 	err = regulator_enable(tdp158->vcc);
28 	if (err)
29 		dev_err(tdp158->dev, "failed to enable vcc: %d", err);
30 
31 	err = regulator_enable(tdp158->vdd);
32 	if (err)
33 		dev_err(tdp158->dev, "failed to enable vdd: %d", err);
34 
35 	gpiod_set_value_cansleep(tdp158->enable, 1);
36 }
37 
tdp158_disable(struct drm_bridge * bridge,struct drm_atomic_state * state)38 static void tdp158_disable(struct drm_bridge *bridge,
39 			   struct drm_atomic_state *state)
40 {
41 	struct tdp158 *tdp158 = bridge->driver_private;
42 
43 	gpiod_set_value_cansleep(tdp158->enable, 0);
44 	regulator_disable(tdp158->vdd);
45 	regulator_disable(tdp158->vcc);
46 }
47 
tdp158_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)48 static int tdp158_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
49 {
50 	struct tdp158 *tdp158 = bridge->driver_private;
51 
52 	return drm_bridge_attach(bridge->encoder, tdp158->next, bridge, flags);
53 }
54 
55 static const struct drm_bridge_funcs tdp158_bridge_funcs = {
56 	.attach = tdp158_attach,
57 	.atomic_enable = tdp158_enable,
58 	.atomic_disable = tdp158_disable,
59 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
60 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
61 	.atomic_reset = drm_atomic_helper_bridge_reset,
62 };
63 
tdp158_probe(struct i2c_client * client)64 static int tdp158_probe(struct i2c_client *client)
65 {
66 	struct tdp158 *tdp158;
67 	struct device *dev = &client->dev;
68 
69 	tdp158 = devm_kzalloc(dev, sizeof(*tdp158), GFP_KERNEL);
70 	if (!tdp158)
71 		return -ENOMEM;
72 
73 	tdp158->next = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
74 	if (IS_ERR(tdp158->next))
75 		return dev_err_probe(dev, PTR_ERR(tdp158->next), "missing bridge");
76 
77 	tdp158->vcc = devm_regulator_get(dev, "vcc");
78 	if (IS_ERR(tdp158->vcc))
79 		return dev_err_probe(dev, PTR_ERR(tdp158->vcc), "vcc");
80 
81 	tdp158->vdd = devm_regulator_get(dev, "vdd");
82 	if (IS_ERR(tdp158->vdd))
83 		return dev_err_probe(dev, PTR_ERR(tdp158->vdd), "vdd");
84 
85 	tdp158->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
86 	if (IS_ERR(tdp158->enable))
87 		return dev_err_probe(dev, PTR_ERR(tdp158->enable), "enable");
88 
89 	tdp158->bridge.of_node = dev->of_node;
90 	tdp158->bridge.funcs = &tdp158_bridge_funcs;
91 	tdp158->bridge.driver_private = tdp158;
92 	tdp158->dev = dev;
93 
94 	return devm_drm_bridge_add(dev, &tdp158->bridge);
95 }
96 
97 static const struct of_device_id tdp158_match_table[] = {
98 	{ .compatible = "ti,tdp158" },
99 	{ }
100 };
101 MODULE_DEVICE_TABLE(of, tdp158_match_table);
102 
103 static struct i2c_driver tdp158_driver = {
104 	.probe = tdp158_probe,
105 	.driver = {
106 		.name = "tdp158",
107 		.of_match_table = tdp158_match_table,
108 	},
109 };
110 module_i2c_driver(tdp158_driver);
111 
112 MODULE_DESCRIPTION("TI TDP158 driver");
113 MODULE_LICENSE("GPL");
114