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