xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/bridge/rohm-bu18rl82.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) Rockchip Electronics Co.Ltd
4  * Author:
5  *      Guochun Huang <hero.huang@rock-chips.com>
6  */
7 
8 #include <asm/unaligned.h>
9 #include <drm/drm_bridge.h>
10 #include <drm/drm_atomic_state_helper.h>
11 #include <drm/drm_mipi_dsi.h>
12 #include <drm/drm_modeset_helper_vtables.h>
13 #include <drm/drm_of.h>
14 #include <drm/drm_print.h>
15 #include <drm/drm_probe_helper.h>
16 #include <drm/drm_panel.h>
17 #include <linux/kernel.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
20 #include <linux/gpio/consumer.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/i2c.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/of_gpio.h>
26 #include <linux/regmap.h>
27 
28 struct serdes_init_seq {
29 	struct reg_sequence *reg_sequence;
30 	unsigned int reg_seq_cnt;
31 };
32 
33 struct bu18rl82 {
34 	struct drm_bridge base;
35 	struct drm_panel *panel;
36 	struct device *dev;
37 	struct regmap *regmap;
38 	struct serdes_init_seq *serdes_init_seq;
39 };
40 
41 static const struct regmap_config bu18rl82_regmap_config = {
42 	.name = "bu18rl82",
43 	.reg_bits = 16,
44 	.val_bits = 8,
45 	.max_register = 0x0700,
46 };
47 
bridge_to_bu18rl82(struct drm_bridge * bridge)48 static struct bu18rl82 *bridge_to_bu18rl82(struct drm_bridge *bridge)
49 {
50 	return container_of(bridge, struct bu18rl82, base);
51 }
52 
bu18rl82_parse_init_seq(struct device * dev,const u16 * data,int length,struct serdes_init_seq * seq)53 static int bu18rl82_parse_init_seq(struct device *dev, const u16 *data,
54 				   int length, struct serdes_init_seq *seq)
55 {
56 	struct reg_sequence *reg_sequence;
57 	u16 *buf, *d;
58 	unsigned int i, cnt;
59 
60 	if (!seq)
61 		return -EINVAL;
62 
63 	buf = devm_kmemdup(dev, data, length, GFP_KERNEL);
64 	if (!buf)
65 		return -ENOMEM;
66 
67 	d = buf;
68 	cnt = length / 4;
69 	seq->reg_seq_cnt = cnt;
70 
71 	seq->reg_sequence = devm_kcalloc(dev, cnt, sizeof(struct reg_sequence), GFP_KERNEL);
72 	if (!seq->reg_sequence)
73 		return -ENOMEM;
74 
75 
76 	for (i = 0; i < cnt; i++) {
77 		reg_sequence = &seq->reg_sequence[i];
78 		reg_sequence->reg = get_unaligned_be16(&d[0]);
79 		reg_sequence->def = get_unaligned_be16(&d[1]);
80 		d += 2;
81 	}
82 
83 	return 0;
84 }
85 
bu18rl82_get_init_seq(struct bu18rl82 * bu18rl82)86 static int bu18rl82_get_init_seq(struct bu18rl82 *bu18rl82)
87 {
88 	struct device *dev = bu18rl82->dev;
89 	struct device_node *np = dev->of_node;
90 	const void *data;
91 	int len, err;
92 
93 	data = of_get_property(np, "serdes-init-sequence", &len);
94 	if (!data) {
95 		dev_err(dev, "failed to get serdes-init-sequence\n");
96 		return -EINVAL;
97 	}
98 
99 	bu18rl82->serdes_init_seq = devm_kzalloc(dev, sizeof(*bu18rl82->serdes_init_seq),
100 						 GFP_KERNEL);
101 	if (!bu18rl82->serdes_init_seq)
102 		return -ENOMEM;
103 
104 	err = bu18rl82_parse_init_seq(dev, data, len, bu18rl82->serdes_init_seq);
105 	if (err) {
106 		dev_err(dev, "failed to parse serdes-init-sequence\n");
107 		return err;
108 	}
109 
110 	return 0;
111 }
112 
bu18rl82_bridge_get_modes(struct drm_bridge * bridge,struct drm_connector * connector)113 static int bu18rl82_bridge_get_modes(struct drm_bridge *bridge,
114 				     struct drm_connector *connector)
115 {
116 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
117 
118 	return drm_panel_get_modes(bu18rl82->panel, connector);
119 }
120 
bu18rl82_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)121 static int bu18rl82_bridge_attach(struct drm_bridge *bridge,
122 				  enum drm_bridge_attach_flags flags)
123 {
124 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
125 	int ret;
126 
127 	ret = drm_of_find_panel_or_bridge(bu18rl82->dev->of_node, 1, -1,
128 					  &bu18rl82->panel, NULL);
129 	if (ret)
130 		return ret;
131 
132 	return 0;
133 }
134 
bu18rl82_bridge_enable(struct drm_bridge * bridge)135 static void bu18rl82_bridge_enable(struct drm_bridge *bridge)
136 {
137 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
138 	struct serdes_init_seq *init_seq = bu18rl82->serdes_init_seq;
139 	int count = init_seq->reg_seq_cnt;
140 
141 	regmap_multi_reg_write(bu18rl82->regmap, init_seq->reg_sequence, count);
142 
143 	drm_panel_enable(bu18rl82->panel);
144 }
145 
bu18rl82_bridge_disable(struct drm_bridge * bridge)146 static void bu18rl82_bridge_disable(struct drm_bridge *bridge)
147 {
148 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
149 
150 	drm_panel_disable(bu18rl82->panel);
151 
152 	regmap_write(bu18rl82->regmap, 0x91, 0x00);
153 }
154 
bu18rl82_bridge_pre_enable(struct drm_bridge * bridge)155 static void bu18rl82_bridge_pre_enable(struct drm_bridge *bridge)
156 {
157 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
158 
159 	drm_panel_prepare(bu18rl82->panel);
160 }
161 
bu18rl82_bridge_post_disable(struct drm_bridge * bridge)162 static void bu18rl82_bridge_post_disable(struct drm_bridge *bridge)
163 {
164 	struct bu18rl82 *bu18rl82 = bridge_to_bu18rl82(bridge);
165 
166 	drm_panel_unprepare(bu18rl82->panel);
167 }
168 
169 static const struct drm_bridge_funcs bu18rl82_bridge_funcs = {
170 	.attach = bu18rl82_bridge_attach,
171 	.enable = bu18rl82_bridge_enable,
172 	.disable = bu18rl82_bridge_disable,
173 	.pre_enable = bu18rl82_bridge_pre_enable,
174 	.post_disable = bu18rl82_bridge_post_disable,
175 	.get_modes = bu18rl82_bridge_get_modes,
176 };
177 
bu18rl82_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)178 static int bu18rl82_i2c_probe(struct i2c_client *client,
179 			      const struct i2c_device_id *id)
180 {
181 	struct device *dev = &client->dev;
182 	struct bu18rl82 *bu18rl82;
183 	int ret;
184 
185 	bu18rl82 = devm_kzalloc(dev, sizeof(*bu18rl82), GFP_KERNEL);
186 	if (!bu18rl82)
187 		return -ENOMEM;
188 
189 	bu18rl82->dev = dev;
190 	i2c_set_clientdata(client, bu18rl82);
191 
192 	bu18rl82->regmap = devm_regmap_init_i2c(client, &bu18rl82_regmap_config);
193 	if (IS_ERR(bu18rl82->regmap))
194 		return dev_err_probe(dev, PTR_ERR(bu18rl82->regmap),
195 				     "failed to initialize regmap\n");
196 
197 	ret = bu18rl82_get_init_seq(bu18rl82);
198 	if (ret)
199 		return ret;
200 
201 	bu18rl82->base.funcs = &bu18rl82_bridge_funcs;
202 	bu18rl82->base.of_node = dev->of_node;
203 	bu18rl82->base.ops = DRM_BRIDGE_OP_MODES;
204 
205 	drm_bridge_add(&bu18rl82->base);
206 
207 	return 0;
208 }
209 
bu18rl82_i2c_remove(struct i2c_client * client)210 static int bu18rl82_i2c_remove(struct i2c_client *client)
211 {
212 	struct bu18rl82 *bu18rl82 = i2c_get_clientdata(client);
213 
214 	drm_bridge_remove(&bu18rl82->base);
215 
216 	return 0;
217 }
218 
219 static const struct i2c_device_id bu18rl82_i2c_table[] = {
220 	{ "bu18rl82", 0 },
221 	{}
222 };
223 MODULE_DEVICE_TABLE(i2c, bu18rl82_i2c_table);
224 
225 static const struct of_device_id bu18rl82_of_match[] = {
226 	{ .compatible = "rohm,bu18rl82" },
227 	{}
228 };
229 MODULE_DEVICE_TABLE(of, bu18rl82_of_match);
230 
231 static struct i2c_driver bu18rl82_i2c_driver = {
232 	.driver = {
233 		.name = "bu18rl82",
234 		.of_match_table = bu18rl82_of_match,
235 	},
236 	.probe = bu18rl82_i2c_probe,
237 	.remove = bu18rl82_i2c_remove,
238 	.id_table = bu18rl82_i2c_table,
239 };
240 module_i2c_driver(bu18rl82_i2c_driver);
241 
242 MODULE_AUTHOR("Guochun Huang <hero.huang@rock-chips.com>");
243 MODULE_DESCRIPTION("Rohm BU18RL82 Clockless Link-BD Deserializer with LVDS Interface");
244 MODULE_LICENSE("GPL");
245