1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for MegaChips STDP4028 with GE B850v3 firmware (LVDS-DP)
4*4882a593Smuzhiyun * Driver for MegaChips STDP2690 with GE B850v3 firmware (DP-DP++)
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun * Copyright (c) 2017, Collabora Ltd.
7*4882a593Smuzhiyun * Copyright (c) 2017, General Electric Company
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
11*4882a593Smuzhiyun * display bridge of the GE B850v3. There are two physical bridges on the video
12*4882a593Smuzhiyun * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The
13*4882a593Smuzhiyun * physical bridges are automatically configured by the input video signal, and
14*4882a593Smuzhiyun * the driver has no access to the video processing pipeline. The driver is
15*4882a593Smuzhiyun * only needed to read EDID from the STDP2690 and to handle HPD events from the
16*4882a593Smuzhiyun * STDP4028. The driver communicates with both bridges over i2c. The video
17*4882a593Smuzhiyun * signal pipeline is as follows:
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/i2c.h>
23*4882a593Smuzhiyun #include <linux/module.h>
24*4882a593Smuzhiyun #include <linux/of.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <drm/drm_atomic.h>
27*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
28*4882a593Smuzhiyun #include <drm/drm_bridge.h>
29*4882a593Smuzhiyun #include <drm/drm_edid.h>
30*4882a593Smuzhiyun #include <drm/drm_print.h>
31*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define EDID_EXT_BLOCK_CNT 0x7E
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define STDP4028_IRQ_OUT_CONF_REG 0x02
36*4882a593Smuzhiyun #define STDP4028_DPTX_IRQ_EN_REG 0x3C
37*4882a593Smuzhiyun #define STDP4028_DPTX_IRQ_STS_REG 0x3D
38*4882a593Smuzhiyun #define STDP4028_DPTX_STS_REG 0x3E
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define STDP4028_DPTX_DP_IRQ_EN 0x1000
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
43*4882a593Smuzhiyun #define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
44*4882a593Smuzhiyun #define STDP4028_DPTX_IRQ_CONFIG \
45*4882a593Smuzhiyun (STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define STDP4028_DPTX_HOTPLUG_STS 0x0200
48*4882a593Smuzhiyun #define STDP4028_DPTX_LINK_STS 0x1000
49*4882a593Smuzhiyun #define STDP4028_CON_STATE_CONNECTED \
50*4882a593Smuzhiyun (STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
53*4882a593Smuzhiyun #define STDP4028_DPTX_LINK_CH_STS 0x2000
54*4882a593Smuzhiyun #define STDP4028_DPTX_IRQ_CLEAR \
55*4882a593Smuzhiyun (STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static DEFINE_MUTEX(ge_b850v3_lvds_dev_mutex);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun struct ge_b850v3_lvds {
60*4882a593Smuzhiyun struct drm_connector connector;
61*4882a593Smuzhiyun struct drm_bridge bridge;
62*4882a593Smuzhiyun struct i2c_client *stdp4028_i2c;
63*4882a593Smuzhiyun struct i2c_client *stdp2690_i2c;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr;
67*4882a593Smuzhiyun
stdp2690_get_edid(struct i2c_client * client)68*4882a593Smuzhiyun static u8 *stdp2690_get_edid(struct i2c_client *client)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct i2c_adapter *adapter = client->adapter;
71*4882a593Smuzhiyun unsigned char start = 0x00;
72*4882a593Smuzhiyun unsigned int total_size;
73*4882a593Smuzhiyun u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun struct i2c_msg msgs[] = {
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun .addr = client->addr,
78*4882a593Smuzhiyun .flags = 0,
79*4882a593Smuzhiyun .len = 1,
80*4882a593Smuzhiyun .buf = &start,
81*4882a593Smuzhiyun }, {
82*4882a593Smuzhiyun .addr = client->addr,
83*4882a593Smuzhiyun .flags = I2C_M_RD,
84*4882a593Smuzhiyun .len = EDID_LENGTH,
85*4882a593Smuzhiyun .buf = block,
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (!block)
90*4882a593Smuzhiyun return NULL;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (i2c_transfer(adapter, msgs, 2) != 2) {
93*4882a593Smuzhiyun DRM_ERROR("Unable to read EDID.\n");
94*4882a593Smuzhiyun goto err;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (!drm_edid_block_valid(block, 0, false, NULL)) {
98*4882a593Smuzhiyun DRM_ERROR("Invalid EDID data\n");
99*4882a593Smuzhiyun goto err;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
103*4882a593Smuzhiyun if (total_size > EDID_LENGTH) {
104*4882a593Smuzhiyun kfree(block);
105*4882a593Smuzhiyun block = kmalloc(total_size, GFP_KERNEL);
106*4882a593Smuzhiyun if (!block)
107*4882a593Smuzhiyun return NULL;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* Yes, read the entire buffer, and do not skip the first
110*4882a593Smuzhiyun * EDID_LENGTH bytes.
111*4882a593Smuzhiyun */
112*4882a593Smuzhiyun start = 0x00;
113*4882a593Smuzhiyun msgs[1].len = total_size;
114*4882a593Smuzhiyun msgs[1].buf = block;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (i2c_transfer(adapter, msgs, 2) != 2) {
117*4882a593Smuzhiyun DRM_ERROR("Unable to read EDID extension blocks.\n");
118*4882a593Smuzhiyun goto err;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun if (!drm_edid_block_valid(block, 1, false, NULL)) {
121*4882a593Smuzhiyun DRM_ERROR("Invalid EDID data\n");
122*4882a593Smuzhiyun goto err;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return block;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun err:
129*4882a593Smuzhiyun kfree(block);
130*4882a593Smuzhiyun return NULL;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
ge_b850v3_lvds_get_edid(struct drm_bridge * bridge,struct drm_connector * connector)133*4882a593Smuzhiyun static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge,
134*4882a593Smuzhiyun struct drm_connector *connector)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun struct i2c_client *client;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun client = ge_b850v3_lvds_ptr->stdp2690_i2c;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun return (struct edid *)stdp2690_get_edid(client);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
ge_b850v3_lvds_get_modes(struct drm_connector * connector)143*4882a593Smuzhiyun static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct edid *edid;
146*4882a593Smuzhiyun int num_modes;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun drm_connector_update_edid_property(connector, edid);
151*4882a593Smuzhiyun num_modes = drm_add_edid_modes(connector, edid);
152*4882a593Smuzhiyun kfree(edid);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun return num_modes;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
ge_b850v3_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)157*4882a593Smuzhiyun static enum drm_mode_status ge_b850v3_lvds_mode_valid(
158*4882a593Smuzhiyun struct drm_connector *connector, struct drm_display_mode *mode)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun return MODE_OK;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun static const struct
164*4882a593Smuzhiyun drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = {
165*4882a593Smuzhiyun .get_modes = ge_b850v3_lvds_get_modes,
166*4882a593Smuzhiyun .mode_valid = ge_b850v3_lvds_mode_valid,
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun
ge_b850v3_lvds_bridge_detect(struct drm_bridge * bridge)169*4882a593Smuzhiyun static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun struct i2c_client *stdp4028_i2c =
172*4882a593Smuzhiyun ge_b850v3_lvds_ptr->stdp4028_i2c;
173*4882a593Smuzhiyun s32 link_state;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun link_state = i2c_smbus_read_word_data(stdp4028_i2c,
176*4882a593Smuzhiyun STDP4028_DPTX_STS_REG);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (link_state == STDP4028_CON_STATE_CONNECTED)
179*4882a593Smuzhiyun return connector_status_connected;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (link_state == 0)
182*4882a593Smuzhiyun return connector_status_disconnected;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun return connector_status_unknown;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
ge_b850v3_lvds_detect(struct drm_connector * connector,bool force)187*4882a593Smuzhiyun static enum drm_connector_status ge_b850v3_lvds_detect(struct drm_connector *connector,
188*4882a593Smuzhiyun bool force)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun return ge_b850v3_lvds_bridge_detect(&ge_b850v3_lvds_ptr->bridge);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
194*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
195*4882a593Smuzhiyun .detect = ge_b850v3_lvds_detect,
196*4882a593Smuzhiyun .destroy = drm_connector_cleanup,
197*4882a593Smuzhiyun .reset = drm_atomic_helper_connector_reset,
198*4882a593Smuzhiyun .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
199*4882a593Smuzhiyun .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun
ge_b850v3_lvds_create_connector(struct drm_bridge * bridge)202*4882a593Smuzhiyun static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector;
205*4882a593Smuzhiyun int ret;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (!bridge->encoder) {
208*4882a593Smuzhiyun DRM_ERROR("Parent encoder object not found");
209*4882a593Smuzhiyun return -ENODEV;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun connector->polled = DRM_CONNECTOR_POLL_HPD;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun drm_connector_helper_add(connector,
215*4882a593Smuzhiyun &ge_b850v3_lvds_connector_helper_funcs);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun ret = drm_connector_init(bridge->dev, connector,
218*4882a593Smuzhiyun &ge_b850v3_lvds_connector_funcs,
219*4882a593Smuzhiyun DRM_MODE_CONNECTOR_DisplayPort);
220*4882a593Smuzhiyun if (ret) {
221*4882a593Smuzhiyun DRM_ERROR("Failed to initialize connector with drm\n");
222*4882a593Smuzhiyun return ret;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun return drm_connector_attach_encoder(connector, bridge->encoder);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
ge_b850v3_lvds_irq_handler(int irq,void * dev_id)228*4882a593Smuzhiyun static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun struct i2c_client *stdp4028_i2c
231*4882a593Smuzhiyun = ge_b850v3_lvds_ptr->stdp4028_i2c;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun i2c_smbus_write_word_data(stdp4028_i2c,
234*4882a593Smuzhiyun STDP4028_DPTX_IRQ_STS_REG,
235*4882a593Smuzhiyun STDP4028_DPTX_IRQ_CLEAR);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (ge_b850v3_lvds_ptr->bridge.dev)
238*4882a593Smuzhiyun drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->bridge.dev);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return IRQ_HANDLED;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
ge_b850v3_lvds_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)243*4882a593Smuzhiyun static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
244*4882a593Smuzhiyun enum drm_bridge_attach_flags flags)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct i2c_client *stdp4028_i2c
247*4882a593Smuzhiyun = ge_b850v3_lvds_ptr->stdp4028_i2c;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* Configures the bridge to re-enable interrupts after each ack. */
250*4882a593Smuzhiyun i2c_smbus_write_word_data(stdp4028_i2c,
251*4882a593Smuzhiyun STDP4028_IRQ_OUT_CONF_REG,
252*4882a593Smuzhiyun STDP4028_DPTX_DP_IRQ_EN);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* Enable interrupts */
255*4882a593Smuzhiyun i2c_smbus_write_word_data(stdp4028_i2c,
256*4882a593Smuzhiyun STDP4028_DPTX_IRQ_EN_REG,
257*4882a593Smuzhiyun STDP4028_DPTX_IRQ_CONFIG);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
260*4882a593Smuzhiyun return 0;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun return ge_b850v3_lvds_create_connector(bridge);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = {
266*4882a593Smuzhiyun .attach = ge_b850v3_lvds_attach,
267*4882a593Smuzhiyun .detect = ge_b850v3_lvds_bridge_detect,
268*4882a593Smuzhiyun .get_edid = ge_b850v3_lvds_get_edid,
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun
ge_b850v3_lvds_init(struct device * dev)271*4882a593Smuzhiyun static int ge_b850v3_lvds_init(struct device *dev)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun mutex_lock(&ge_b850v3_lvds_dev_mutex);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (ge_b850v3_lvds_ptr)
276*4882a593Smuzhiyun goto success;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun ge_b850v3_lvds_ptr = devm_kzalloc(dev,
279*4882a593Smuzhiyun sizeof(*ge_b850v3_lvds_ptr),
280*4882a593Smuzhiyun GFP_KERNEL);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (!ge_b850v3_lvds_ptr) {
283*4882a593Smuzhiyun mutex_unlock(&ge_b850v3_lvds_dev_mutex);
284*4882a593Smuzhiyun return -ENOMEM;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun success:
288*4882a593Smuzhiyun mutex_unlock(&ge_b850v3_lvds_dev_mutex);
289*4882a593Smuzhiyun return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
ge_b850v3_lvds_remove(void)292*4882a593Smuzhiyun static void ge_b850v3_lvds_remove(void)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun mutex_lock(&ge_b850v3_lvds_dev_mutex);
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * This check is to avoid both the drivers
297*4882a593Smuzhiyun * removing the bridge in their remove() function
298*4882a593Smuzhiyun */
299*4882a593Smuzhiyun if (!ge_b850v3_lvds_ptr ||
300*4882a593Smuzhiyun !ge_b850v3_lvds_ptr->stdp2690_i2c ||
301*4882a593Smuzhiyun !ge_b850v3_lvds_ptr->stdp4028_i2c)
302*4882a593Smuzhiyun goto out;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun ge_b850v3_lvds_ptr = NULL;
307*4882a593Smuzhiyun out:
308*4882a593Smuzhiyun mutex_unlock(&ge_b850v3_lvds_dev_mutex);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
ge_b850v3_register(void)311*4882a593Smuzhiyun static int ge_b850v3_register(void)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun struct i2c_client *stdp4028_i2c = ge_b850v3_lvds_ptr->stdp4028_i2c;
314*4882a593Smuzhiyun struct device *dev = &stdp4028_i2c->dev;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /* drm bridge initialization */
317*4882a593Smuzhiyun ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
318*4882a593Smuzhiyun ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT |
319*4882a593Smuzhiyun DRM_BRIDGE_OP_EDID;
320*4882a593Smuzhiyun ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
321*4882a593Smuzhiyun ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node;
322*4882a593Smuzhiyun drm_bridge_add(&ge_b850v3_lvds_ptr->bridge);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* Clear pending interrupts since power up. */
325*4882a593Smuzhiyun i2c_smbus_write_word_data(stdp4028_i2c,
326*4882a593Smuzhiyun STDP4028_DPTX_IRQ_STS_REG,
327*4882a593Smuzhiyun STDP4028_DPTX_IRQ_CLEAR);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (!stdp4028_i2c->irq)
330*4882a593Smuzhiyun return 0;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun return devm_request_threaded_irq(&stdp4028_i2c->dev,
333*4882a593Smuzhiyun stdp4028_i2c->irq, NULL,
334*4882a593Smuzhiyun ge_b850v3_lvds_irq_handler,
335*4882a593Smuzhiyun IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
336*4882a593Smuzhiyun "ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
stdp4028_ge_b850v3_fw_probe(struct i2c_client * stdp4028_i2c,const struct i2c_device_id * id)339*4882a593Smuzhiyun static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
340*4882a593Smuzhiyun const struct i2c_device_id *id)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun struct device *dev = &stdp4028_i2c->dev;
343*4882a593Smuzhiyun int ret;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun ret = ge_b850v3_lvds_init(dev);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (ret)
348*4882a593Smuzhiyun return ret;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c;
351*4882a593Smuzhiyun i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* Only register after both bridges are probed */
354*4882a593Smuzhiyun if (!ge_b850v3_lvds_ptr->stdp2690_i2c)
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun return ge_b850v3_register();
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
stdp4028_ge_b850v3_fw_remove(struct i2c_client * stdp4028_i2c)360*4882a593Smuzhiyun static int stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun ge_b850v3_lvds_remove();
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {
368*4882a593Smuzhiyun {"stdp4028_ge_fw", 0},
369*4882a593Smuzhiyun {},
370*4882a593Smuzhiyun };
371*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun static const struct of_device_id stdp4028_ge_b850v3_fw_match[] = {
374*4882a593Smuzhiyun { .compatible = "megachips,stdp4028-ge-b850v3-fw" },
375*4882a593Smuzhiyun {},
376*4882a593Smuzhiyun };
377*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
380*4882a593Smuzhiyun .id_table = stdp4028_ge_b850v3_fw_i2c_table,
381*4882a593Smuzhiyun .probe = stdp4028_ge_b850v3_fw_probe,
382*4882a593Smuzhiyun .remove = stdp4028_ge_b850v3_fw_remove,
383*4882a593Smuzhiyun .driver = {
384*4882a593Smuzhiyun .name = "stdp4028-ge-b850v3-fw",
385*4882a593Smuzhiyun .of_match_table = stdp4028_ge_b850v3_fw_match,
386*4882a593Smuzhiyun },
387*4882a593Smuzhiyun };
388*4882a593Smuzhiyun
stdp2690_ge_b850v3_fw_probe(struct i2c_client * stdp2690_i2c,const struct i2c_device_id * id)389*4882a593Smuzhiyun static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c,
390*4882a593Smuzhiyun const struct i2c_device_id *id)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct device *dev = &stdp2690_i2c->dev;
393*4882a593Smuzhiyun int ret;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun ret = ge_b850v3_lvds_init(dev);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (ret)
398*4882a593Smuzhiyun return ret;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c;
401*4882a593Smuzhiyun i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /* Only register after both bridges are probed */
404*4882a593Smuzhiyun if (!ge_b850v3_lvds_ptr->stdp4028_i2c)
405*4882a593Smuzhiyun return 0;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return ge_b850v3_register();
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
stdp2690_ge_b850v3_fw_remove(struct i2c_client * stdp2690_i2c)410*4882a593Smuzhiyun static int stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun ge_b850v3_lvds_remove();
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {
418*4882a593Smuzhiyun {"stdp2690_ge_fw", 0},
419*4882a593Smuzhiyun {},
420*4882a593Smuzhiyun };
421*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static const struct of_device_id stdp2690_ge_b850v3_fw_match[] = {
424*4882a593Smuzhiyun { .compatible = "megachips,stdp2690-ge-b850v3-fw" },
425*4882a593Smuzhiyun {},
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun static struct i2c_driver stdp2690_ge_b850v3_fw_driver = {
430*4882a593Smuzhiyun .id_table = stdp2690_ge_b850v3_fw_i2c_table,
431*4882a593Smuzhiyun .probe = stdp2690_ge_b850v3_fw_probe,
432*4882a593Smuzhiyun .remove = stdp2690_ge_b850v3_fw_remove,
433*4882a593Smuzhiyun .driver = {
434*4882a593Smuzhiyun .name = "stdp2690-ge-b850v3-fw",
435*4882a593Smuzhiyun .of_match_table = stdp2690_ge_b850v3_fw_match,
436*4882a593Smuzhiyun },
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun
stdpxxxx_ge_b850v3_init(void)439*4882a593Smuzhiyun static int __init stdpxxxx_ge_b850v3_init(void)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun int ret;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun ret = i2c_add_driver(&stdp4028_ge_b850v3_fw_driver);
444*4882a593Smuzhiyun if (ret)
445*4882a593Smuzhiyun return ret;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun module_init(stdpxxxx_ge_b850v3_init);
450*4882a593Smuzhiyun
stdpxxxx_ge_b850v3_exit(void)451*4882a593Smuzhiyun static void __exit stdpxxxx_ge_b850v3_exit(void)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun i2c_del_driver(&stdp2690_ge_b850v3_fw_driver);
454*4882a593Smuzhiyun i2c_del_driver(&stdp4028_ge_b850v3_fw_driver);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun module_exit(stdpxxxx_ge_b850v3_exit);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun MODULE_AUTHOR("Peter Senna Tschudin <peter.senna@collabora.com>");
459*4882a593Smuzhiyun MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk>");
460*4882a593Smuzhiyun MODULE_DESCRIPTION("GE LVDS to DP++ display bridge)");
461*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
462