xref: /rk3399_rockchip-uboot/drivers/video/drm/rohm-bu18rl82.c (revision 7e044b9aeceaa3c07ba4dd8939761bd87f4c8300)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <i2c.h>
10 #include <video_bridge.h>
11 #include <asm/unaligned.h>
12 #include <linux/media-bus-format.h>
13 #include <power/regulator.h>
14 
15 #include "rockchip_bridge.h"
16 #include "rockchip_display.h"
17 #include "rockchip_panel.h"
18 
19 struct des_reg_sequence {
20 	uint reg;
21 	uint def;
22 };
23 
24 struct serdes_init_seq {
25 	struct des_reg_sequence *reg_sequence;
26 	uint reg_seq_cnt;
27 };
28 
29 struct bu18rl82_priv {
30 	struct udevice *dev;
31 	struct serdes_init_seq *serdes_init_seq;
32 };
33 
34 static void bu18rl82_serdes_init_sequence_write(struct bu18rl82_priv *priv)
35 {
36 	struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq;
37 	struct des_reg_sequence *reg_sequence =  serdes_init_seq->reg_sequence;
38 	uint cnt = serdes_init_seq->reg_seq_cnt;
39 	struct udevice *dev = priv->dev;
40 	uint i;
41 	int ret;
42 
43 	for (i = 0; i < cnt; i++) {
44 		ret = dm_i2c_reg_write(dev, reg_sequence[i].reg, reg_sequence[i].def);
45 		if (ret < 0)
46 			dev_err(priv->dev, "write reg: 0x%04x\n", reg_sequence[i].reg);
47 	}
48 }
49 
50 static void bu18rl82_bridge_enable(struct rockchip_bridge *bridge)
51 {
52 	struct udevice *dev = bridge->dev;
53 	struct bu18rl82_priv *priv = dev_get_priv(dev);
54 
55 	bu18rl82_serdes_init_sequence_write(priv);
56 }
57 
58 static const struct rockchip_bridge_funcs bu18rl82_bridge_funcs = {
59 	.enable = bu18rl82_bridge_enable,
60 };
61 
62 static int bu18rl82_parse_init_seq(struct udevice *dev, const u16 *data,
63 				   int length, struct serdes_init_seq *seq)
64 {
65 	struct des_reg_sequence *reg_sequence;
66 	u16 *buf, *d;
67 	unsigned int i, cnt;
68 	int ret;
69 
70 	if (!seq)
71 		return -EINVAL;
72 
73 	buf = calloc(1, length);
74 	if (!buf)
75 		return -ENOMEM;
76 
77 	memcpy(buf, data, length);
78 
79 	d = buf;
80 	cnt = length / 4;
81 	seq->reg_seq_cnt = cnt;
82 
83 	seq->reg_sequence = calloc(cnt, sizeof(struct des_reg_sequence));
84 	if (!seq->reg_sequence) {
85 		ret = -ENOMEM;
86 		goto free_buf;
87 	}
88 
89 	for (i = 0; i < cnt; i++) {
90 		reg_sequence = &seq->reg_sequence[i];
91 		reg_sequence->reg = get_unaligned_be16(&d[0]);
92 		reg_sequence->def = get_unaligned_be16(&d[1]);
93 		d += 2;
94 	}
95 
96 	return 0;
97 
98 free_buf:
99 	free(buf);
100 
101 	return ret;
102 }
103 
104 static int bu18rl82_get_init_seq(struct bu18rl82_priv *priv)
105 {
106 	const void *data = NULL;
107 	int len, err;
108 
109 	data = dev_read_prop(priv->dev, "serdes-init-sequence", &len);
110 	if (!data) {
111 		printf("failed to get serdes-init-sequence\n");
112 		return -EINVAL;
113 	}
114 
115 	priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq));
116 	if (!priv->serdes_init_seq)
117 		return -ENOMEM;
118 
119 	err = bu18rl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq);
120 	if (err) {
121 		printf("failed to parse serdes-init-sequence\n");
122 		goto free_init_seq;
123 	}
124 
125 	return 0;
126 
127 free_init_seq:
128 	free(priv->serdes_init_seq);
129 
130 	return err;
131 }
132 
133 static int bu18rl82_probe(struct udevice *dev)
134 {
135 	struct bu18rl82_priv *priv = dev_get_priv(dev);
136 	struct rockchip_bridge *bridge;
137 	int ret;
138 
139 	ret = i2c_set_chip_offset_len(dev, 2);
140 	if (ret)
141 		return ret;
142 
143 	priv->dev = dev;
144 
145 	bridge = calloc(1, sizeof(*bridge));
146 	if (!bridge)
147 		return -ENOMEM;
148 
149 	ret = bu18rl82_get_init_seq(priv);
150 	if (ret)
151 		goto free_bridge;
152 
153 	dev->driver_data = (ulong)bridge;
154 	bridge->dev = dev;
155 	bridge->funcs = &bu18rl82_bridge_funcs;
156 
157 	return 0;
158 
159 free_bridge:
160 	free(bridge);
161 
162 	return ret;
163 }
164 
165 static const struct udevice_id bu18rl82_of_match[] = {
166 	{ .compatible = "rohm,bu18rl82", },
167 	{}
168 };
169 
170 U_BOOT_DRIVER(bu18rl82) = {
171 	.name = "bu18rl82",
172 	.id = UCLASS_VIDEO_BRIDGE,
173 	.of_match = bu18rl82_of_match,
174 	.probe = bu18rl82_probe,
175 	.priv_auto_alloc_size = sizeof(struct bu18rl82_priv),
176 };
177