Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/bridge/ti-tdp158.c
26494 views
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
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
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
48
static int tdp158_attach(struct drm_bridge *bridge,
49
struct drm_encoder *encoder,
50
enum drm_bridge_attach_flags flags)
51
{
52
struct tdp158 *tdp158 = bridge->driver_private;
53
54
return drm_bridge_attach(encoder, tdp158->next, bridge, flags);
55
}
56
57
static const struct drm_bridge_funcs tdp158_bridge_funcs = {
58
.attach = tdp158_attach,
59
.atomic_enable = tdp158_enable,
60
.atomic_disable = tdp158_disable,
61
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
62
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
63
.atomic_reset = drm_atomic_helper_bridge_reset,
64
};
65
66
static int tdp158_probe(struct i2c_client *client)
67
{
68
struct tdp158 *tdp158;
69
struct device *dev = &client->dev;
70
71
tdp158 = devm_drm_bridge_alloc(dev, struct tdp158, bridge,
72
&tdp158_bridge_funcs);
73
if (IS_ERR(tdp158))
74
return PTR_ERR(tdp158);
75
76
tdp158->next = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
77
if (IS_ERR(tdp158->next))
78
return dev_err_probe(dev, PTR_ERR(tdp158->next), "missing bridge");
79
80
tdp158->vcc = devm_regulator_get(dev, "vcc");
81
if (IS_ERR(tdp158->vcc))
82
return dev_err_probe(dev, PTR_ERR(tdp158->vcc), "vcc");
83
84
tdp158->vdd = devm_regulator_get(dev, "vdd");
85
if (IS_ERR(tdp158->vdd))
86
return dev_err_probe(dev, PTR_ERR(tdp158->vdd), "vdd");
87
88
tdp158->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
89
if (IS_ERR(tdp158->enable))
90
return dev_err_probe(dev, PTR_ERR(tdp158->enable), "enable");
91
92
tdp158->bridge.of_node = dev->of_node;
93
tdp158->bridge.driver_private = tdp158;
94
tdp158->dev = dev;
95
96
return devm_drm_bridge_add(dev, &tdp158->bridge);
97
}
98
99
static const struct of_device_id tdp158_match_table[] = {
100
{ .compatible = "ti,tdp158" },
101
{ }
102
};
103
MODULE_DEVICE_TABLE(of, tdp158_match_table);
104
105
static struct i2c_driver tdp158_driver = {
106
.probe = tdp158_probe,
107
.driver = {
108
.name = "tdp158",
109
.of_match_table = tdp158_match_table,
110
},
111
};
112
module_i2c_driver(tdp158_driver);
113
114
MODULE_DESCRIPTION("TI TDP158 driver");
115
MODULE_LICENSE("GPL");
116
117