blob: 959e2074b0d4299c10d45311fbce06c13ab58d0c [file] [log] [blame]
Keith Packarda4fc5ed2009-04-07 16:16:42 -07001/*
2 * Copyright © 2009 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/delay.h>
Keith Packarda4fc5ed2009-04-07 16:16:42 -070026#include <linux/init.h>
27#include <linux/errno.h>
28#include <linux/sched.h>
29#include <linux/i2c.h>
David Howells760285e2012-10-02 18:01:07 +010030#include <drm/drm_dp_helper.h>
31#include <drm/drmP.h>
Keith Packarda4fc5ed2009-04-07 16:16:42 -070032
Daniel Vetter28164fd2012-11-01 14:45:18 +010033/**
34 * DOC: dp helpers
35 *
36 * These functions contain some common logic and helpers at various abstraction
37 * levels to deal with Display Port sink devices and related things like DP aux
38 * channel transfers, EDID reading over DP aux channels, decoding certain DPCD
39 * blocks, ...
40 */
41
Daniel Vetter1ffdff12012-10-18 10:15:24 +020042/* Helpers for DP link training */
Jani Nikula0aec2882013-09-27 19:01:01 +030043static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
Daniel Vetter1ffdff12012-10-18 10:15:24 +020044{
45 return link_status[r - DP_LANE0_1_STATUS];
46}
47
Jani Nikula0aec2882013-09-27 19:01:01 +030048static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE],
Daniel Vetter1ffdff12012-10-18 10:15:24 +020049 int lane)
50{
51 int i = DP_LANE0_1_STATUS + (lane >> 1);
52 int s = (lane & 1) * 4;
53 u8 l = dp_link_status(link_status, i);
54 return (l >> s) & 0xf;
55}
56
Jani Nikula0aec2882013-09-27 19:01:01 +030057bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
Daniel Vetter1ffdff12012-10-18 10:15:24 +020058 int lane_count)
59{
60 u8 lane_align;
61 u8 lane_status;
62 int lane;
63
64 lane_align = dp_link_status(link_status,
65 DP_LANE_ALIGN_STATUS_UPDATED);
66 if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
67 return false;
68 for (lane = 0; lane < lane_count; lane++) {
69 lane_status = dp_get_lane_status(link_status, lane);
70 if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
71 return false;
72 }
73 return true;
74}
75EXPORT_SYMBOL(drm_dp_channel_eq_ok);
76
Jani Nikula0aec2882013-09-27 19:01:01 +030077bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
Daniel Vetter1ffdff12012-10-18 10:15:24 +020078 int lane_count)
79{
80 int lane;
81 u8 lane_status;
82
83 for (lane = 0; lane < lane_count; lane++) {
84 lane_status = dp_get_lane_status(link_status, lane);
85 if ((lane_status & DP_LANE_CR_DONE) == 0)
86 return false;
87 }
88 return true;
89}
90EXPORT_SYMBOL(drm_dp_clock_recovery_ok);
Daniel Vetter0f037bd2012-10-18 10:15:27 +020091
Jani Nikula0aec2882013-09-27 19:01:01 +030092u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE],
Daniel Vetter0f037bd2012-10-18 10:15:27 +020093 int lane)
94{
95 int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
96 int s = ((lane & 1) ?
97 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
98 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
99 u8 l = dp_link_status(link_status, i);
100
101 return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
102}
103EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage);
104
Jani Nikula0aec2882013-09-27 19:01:01 +0300105u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE],
Daniel Vetter0f037bd2012-10-18 10:15:27 +0200106 int lane)
107{
108 int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
109 int s = ((lane & 1) ?
110 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
111 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
112 u8 l = dp_link_status(link_status, i);
113
114 return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
115}
116EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
117
Jani Nikula0aec2882013-09-27 19:01:01 +0300118void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
Daniel Vetter1a644cd2012-10-18 15:32:40 +0200119 if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
120 udelay(100);
121 else
122 mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
123}
124EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
125
Jani Nikula0aec2882013-09-27 19:01:01 +0300126void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
Daniel Vetter1a644cd2012-10-18 15:32:40 +0200127 if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
128 udelay(400);
129 else
130 mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
131}
132EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
Daniel Vetter3b5c6622012-10-18 10:15:31 +0200133
134u8 drm_dp_link_rate_to_bw_code(int link_rate)
135{
136 switch (link_rate) {
137 case 162000:
138 default:
139 return DP_LINK_BW_1_62;
140 case 270000:
141 return DP_LINK_BW_2_7;
142 case 540000:
143 return DP_LINK_BW_5_4;
144 }
145}
146EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
147
148int drm_dp_bw_code_to_link_rate(u8 link_bw)
149{
150 switch (link_bw) {
151 case DP_LINK_BW_1_62:
152 default:
153 return 162000;
154 case DP_LINK_BW_2_7:
155 return 270000;
156 case DP_LINK_BW_5_4:
157 return 540000;
158 }
159}
160EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
Thierry Redingc197db72013-11-28 11:31:00 +0100161
162/**
163 * DOC: dp helpers
164 *
165 * The DisplayPort AUX channel is an abstraction to allow generic, driver-
166 * independent access to AUX functionality. Drivers can take advantage of
167 * this by filling in the fields of the drm_dp_aux structure.
168 *
169 * Transactions are described using a hardware-independent drm_dp_aux_msg
170 * structure, which is passed into a driver's .transfer() implementation.
171 * Both native and I2C-over-AUX transactions are supported.
Thierry Redingc197db72013-11-28 11:31:00 +0100172 */
173
174static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
175 unsigned int offset, void *buffer, size_t size)
176{
177 struct drm_dp_aux_msg msg;
178 unsigned int retry;
179 int err;
180
181 memset(&msg, 0, sizeof(msg));
182 msg.address = offset;
183 msg.request = request;
184 msg.buffer = buffer;
185 msg.size = size;
186
187 /*
188 * The specification doesn't give any recommendation on how often to
189 * retry native transactions, so retry 7 times like for I2C-over-AUX
190 * transactions.
191 */
192 for (retry = 0; retry < 7; retry++) {
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000193
194 mutex_lock(&aux->hw_mutex);
Thierry Redingc197db72013-11-28 11:31:00 +0100195 err = aux->transfer(aux, &msg);
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000196 mutex_unlock(&aux->hw_mutex);
Thierry Redingc197db72013-11-28 11:31:00 +0100197 if (err < 0) {
198 if (err == -EBUSY)
199 continue;
200
201 return err;
202 }
203
Thierry Redingc197db72013-11-28 11:31:00 +0100204
205 switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
206 case DP_AUX_NATIVE_REPLY_ACK:
Dave Airlieaa17edf2014-04-04 11:34:37 +1000207 if (err < size)
208 return -EPROTO;
Thierry Redingc197db72013-11-28 11:31:00 +0100209 return err;
210
211 case DP_AUX_NATIVE_REPLY_NACK:
212 return -EIO;
213
214 case DP_AUX_NATIVE_REPLY_DEFER:
215 usleep_range(400, 500);
216 break;
217 }
218 }
219
Alex Deucher743b1e32014-03-21 10:34:06 -0400220 DRM_DEBUG_KMS("too many retries, giving up\n");
Thierry Redingc197db72013-11-28 11:31:00 +0100221 return -EIO;
222}
223
224/**
225 * drm_dp_dpcd_read() - read a series of bytes from the DPCD
226 * @aux: DisplayPort AUX channel
227 * @offset: address of the (first) register to read
228 * @buffer: buffer to store the register values
229 * @size: number of bytes in @buffer
230 *
231 * Returns the number of bytes transferred on success, or a negative error
232 * code on failure. -EIO is returned if the request was NAKed by the sink or
233 * if the retry count was exceeded. If not all bytes were transferred, this
234 * function returns -EPROTO. Errors from the underlying AUX channel transfer
235 * function, with the exception of -EBUSY (which causes the transaction to
236 * be retried), are propagated to the caller.
237 */
238ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
239 void *buffer, size_t size)
240{
241 return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
242 size);
243}
244EXPORT_SYMBOL(drm_dp_dpcd_read);
245
246/**
247 * drm_dp_dpcd_write() - write a series of bytes to the DPCD
248 * @aux: DisplayPort AUX channel
249 * @offset: address of the (first) register to write
250 * @buffer: buffer containing the values to write
251 * @size: number of bytes in @buffer
252 *
253 * Returns the number of bytes transferred on success, or a negative error
254 * code on failure. -EIO is returned if the request was NAKed by the sink or
255 * if the retry count was exceeded. If not all bytes were transferred, this
256 * function returns -EPROTO. Errors from the underlying AUX channel transfer
257 * function, with the exception of -EBUSY (which causes the transaction to
258 * be retried), are propagated to the caller.
259 */
260ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
261 void *buffer, size_t size)
262{
263 return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer,
264 size);
265}
266EXPORT_SYMBOL(drm_dp_dpcd_write);
Thierry Reding8d4adc62013-11-22 16:37:57 +0100267
268/**
269 * drm_dp_dpcd_read_link_status() - read DPCD link status (bytes 0x202-0x207)
270 * @aux: DisplayPort AUX channel
271 * @status: buffer to store the link status in (must be at least 6 bytes)
272 *
273 * Returns the number of bytes transferred on success or a negative error
274 * code on failure.
275 */
276int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
277 u8 status[DP_LINK_STATUS_SIZE])
278{
279 return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status,
280 DP_LINK_STATUS_SIZE);
281}
282EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);
Thierry Reding516c0f72013-12-09 11:47:55 +0100283
284/**
285 * drm_dp_link_probe() - probe a DisplayPort link for capabilities
286 * @aux: DisplayPort AUX channel
287 * @link: pointer to structure in which to return link capabilities
288 *
289 * The structure filled in by this function can usually be passed directly
290 * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
291 * configure the link based on the link's capabilities.
292 *
293 * Returns 0 on success or a negative error code on failure.
294 */
295int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
296{
297 u8 values[3];
298 int err;
299
300 memset(link, 0, sizeof(*link));
301
302 err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
303 if (err < 0)
304 return err;
305
306 link->revision = values[0];
307 link->rate = drm_dp_bw_code_to_link_rate(values[1]);
308 link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
309
310 if (values[2] & DP_ENHANCED_FRAME_CAP)
311 link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
312
313 return 0;
314}
315EXPORT_SYMBOL(drm_dp_link_probe);
316
317/**
318 * drm_dp_link_power_up() - power up a DisplayPort link
319 * @aux: DisplayPort AUX channel
320 * @link: pointer to a structure containing the link configuration
321 *
322 * Returns 0 on success or a negative error code on failure.
323 */
324int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
325{
326 u8 value;
327 int err;
328
329 /* DP_SET_POWER register is only available on DPCD v1.1 and later */
330 if (link->revision < 0x11)
331 return 0;
332
333 err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
334 if (err < 0)
335 return err;
336
337 value &= ~DP_SET_POWER_MASK;
338 value |= DP_SET_POWER_D0;
339
340 err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
341 if (err < 0)
342 return err;
343
344 /*
345 * According to the DP 1.1 specification, a "Sink Device must exit the
346 * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
347 * Control Field" (register 0x600).
348 */
349 usleep_range(1000, 2000);
350
351 return 0;
352}
353EXPORT_SYMBOL(drm_dp_link_power_up);
354
355/**
356 * drm_dp_link_configure() - configure a DisplayPort link
357 * @aux: DisplayPort AUX channel
358 * @link: pointer to a structure containing the link configuration
359 *
360 * Returns 0 on success or a negative error code on failure.
361 */
362int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
363{
364 u8 values[2];
365 int err;
366
367 values[0] = drm_dp_link_rate_to_bw_code(link->rate);
368 values[1] = link->num_lanes;
369
370 if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
371 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
372
373 err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
374 if (err < 0)
375 return err;
376
377 return 0;
378}
379EXPORT_SYMBOL(drm_dp_link_configure);
Thierry Reding88759682013-12-12 09:57:53 +0100380
381/*
382 * I2C-over-AUX implementation
383 */
384
385static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
386{
387 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
388 I2C_FUNC_SMBUS_READ_BLOCK_DATA |
389 I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
390 I2C_FUNC_10BIT_ADDR;
391}
392
393/*
394 * Transfer a single I2C-over-AUX message and handle various error conditions,
Alex Deucher732d50b2014-04-07 10:33:45 -0400395 * retrying the transaction as appropriate. It is assumed that the
396 * aux->transfer function does not modify anything in the msg other than the
397 * reply field.
Thierry Reding88759682013-12-12 09:57:53 +0100398 */
399static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
400{
401 unsigned int retry;
402 int err;
403
404 /*
405 * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
406 * is required to retry at least seven times upon receiving AUX_DEFER
407 * before giving up the AUX transaction.
408 */
409 for (retry = 0; retry < 7; retry++) {
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000410 mutex_lock(&aux->hw_mutex);
Thierry Reding88759682013-12-12 09:57:53 +0100411 err = aux->transfer(aux, msg);
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000412 mutex_unlock(&aux->hw_mutex);
Thierry Reding88759682013-12-12 09:57:53 +0100413 if (err < 0) {
414 if (err == -EBUSY)
415 continue;
416
417 DRM_DEBUG_KMS("transaction failed: %d\n", err);
418 return err;
419 }
420
Thierry Reding88759682013-12-12 09:57:53 +0100421
422 switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) {
423 case DP_AUX_NATIVE_REPLY_ACK:
424 /*
425 * For I2C-over-AUX transactions this isn't enough, we
426 * need to check for the I2C ACK reply.
427 */
428 break;
429
430 case DP_AUX_NATIVE_REPLY_NACK:
431 DRM_DEBUG_KMS("native nack\n");
432 return -EREMOTEIO;
433
434 case DP_AUX_NATIVE_REPLY_DEFER:
435 DRM_DEBUG_KMS("native defer");
436 /*
437 * We could check for I2C bit rate capabilities and if
438 * available adjust this interval. We could also be
439 * more careful with DP-to-legacy adapters where a
440 * long legacy cable may force very low I2C bit rates.
441 *
442 * For now just defer for long enough to hopefully be
443 * safe for all use-cases.
444 */
445 usleep_range(500, 600);
446 continue;
447
448 default:
449 DRM_ERROR("invalid native reply %#04x\n", msg->reply);
450 return -EREMOTEIO;
451 }
452
453 switch (msg->reply & DP_AUX_I2C_REPLY_MASK) {
454 case DP_AUX_I2C_REPLY_ACK:
455 /*
456 * Both native ACK and I2C ACK replies received. We
457 * can assume the transfer was successful.
458 */
Dave Airlieaa17edf2014-04-04 11:34:37 +1000459 if (err < msg->size)
460 return -EPROTO;
Thierry Reding88759682013-12-12 09:57:53 +0100461 return 0;
462
463 case DP_AUX_I2C_REPLY_NACK:
464 DRM_DEBUG_KMS("I2C nack\n");
Todd Previtee9cf6192014-11-04 15:17:35 -0700465 aux->i2c_nack_count++;
Thierry Reding88759682013-12-12 09:57:53 +0100466 return -EREMOTEIO;
467
468 case DP_AUX_I2C_REPLY_DEFER:
469 DRM_DEBUG_KMS("I2C defer\n");
Todd Previtee9cf6192014-11-04 15:17:35 -0700470 aux->i2c_defer_count++;
Thierry Reding88759682013-12-12 09:57:53 +0100471 usleep_range(400, 500);
472 continue;
473
474 default:
475 DRM_ERROR("invalid I2C reply %#04x\n", msg->reply);
476 return -EREMOTEIO;
477 }
478 }
479
Alex Deucher743b1e32014-03-21 10:34:06 -0400480 DRM_DEBUG_KMS("too many retries, giving up\n");
Thierry Reding88759682013-12-12 09:57:53 +0100481 return -EREMOTEIO;
482}
483
484static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
485 int num)
486{
487 struct drm_dp_aux *aux = adapter->algo_data;
488 unsigned int i, j;
Alex Deucherccdb5162014-04-07 10:33:44 -0400489 struct drm_dp_aux_msg msg;
490 int err = 0;
491
492 memset(&msg, 0, sizeof(msg));
Thierry Reding88759682013-12-12 09:57:53 +0100493
494 for (i = 0; i < num; i++) {
Alex Deucherccdb5162014-04-07 10:33:44 -0400495 msg.address = msgs[i].addr;
496 msg.request = (msgs[i].flags & I2C_M_RD) ?
497 DP_AUX_I2C_READ :
498 DP_AUX_I2C_WRITE;
499 msg.request |= DP_AUX_I2C_MOT;
500 /* Send a bare address packet to start the transaction.
501 * Zero sized messages specify an address only (bare
502 * address) transaction.
503 */
504 msg.buffer = NULL;
505 msg.size = 0;
506 err = drm_dp_i2c_do_msg(aux, &msg);
507 if (err < 0)
508 break;
Thierry Reding88759682013-12-12 09:57:53 +0100509 /*
510 * Many hardware implementations support FIFOs larger than a
511 * single byte, but it has been empirically determined that
512 * transferring data in larger chunks can actually lead to
513 * decreased performance. Therefore each message is simply
514 * transferred byte-by-byte.
515 */
516 for (j = 0; j < msgs[i].len; j++) {
Thierry Reding88759682013-12-12 09:57:53 +0100517 msg.buffer = msgs[i].buf + j;
518 msg.size = 1;
519
520 err = drm_dp_i2c_do_msg(aux, &msg);
521 if (err < 0)
Alex Deucherccdb5162014-04-07 10:33:44 -0400522 break;
Thierry Reding88759682013-12-12 09:57:53 +0100523 }
Alex Deucherccdb5162014-04-07 10:33:44 -0400524 if (err < 0)
525 break;
Thierry Reding88759682013-12-12 09:57:53 +0100526 }
Alex Deucherccdb5162014-04-07 10:33:44 -0400527 if (err >= 0)
528 err = num;
529 /* Send a bare address packet to close out the transaction.
530 * Zero sized messages specify an address only (bare
531 * address) transaction.
532 */
533 msg.request &= ~DP_AUX_I2C_MOT;
534 msg.buffer = NULL;
535 msg.size = 0;
536 (void)drm_dp_i2c_do_msg(aux, &msg);
Thierry Reding88759682013-12-12 09:57:53 +0100537
Alex Deucherccdb5162014-04-07 10:33:44 -0400538 return err;
Thierry Reding88759682013-12-12 09:57:53 +0100539}
540
541static const struct i2c_algorithm drm_dp_i2c_algo = {
542 .functionality = drm_dp_i2c_functionality,
543 .master_xfer = drm_dp_i2c_xfer,
544};
545
546/**
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000547 * drm_dp_aux_register() - initialise and register aux channel
Thierry Reding88759682013-12-12 09:57:53 +0100548 * @aux: DisplayPort AUX channel
549 *
550 * Returns 0 on success or a negative error code on failure.
551 */
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000552int drm_dp_aux_register(struct drm_dp_aux *aux)
Thierry Reding88759682013-12-12 09:57:53 +0100553{
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000554 mutex_init(&aux->hw_mutex);
555
Thierry Reding88759682013-12-12 09:57:53 +0100556 aux->ddc.algo = &drm_dp_i2c_algo;
557 aux->ddc.algo_data = aux;
558 aux->ddc.retries = 3;
559
560 aux->ddc.class = I2C_CLASS_DDC;
561 aux->ddc.owner = THIS_MODULE;
562 aux->ddc.dev.parent = aux->dev;
563 aux->ddc.dev.of_node = aux->dev->of_node;
564
Jani Nikula9dc40562014-03-14 16:51:12 +0200565 strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
566 sizeof(aux->ddc.name));
Thierry Reding88759682013-12-12 09:57:53 +0100567
568 return i2c_add_adapter(&aux->ddc);
569}
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000570EXPORT_SYMBOL(drm_dp_aux_register);
Thierry Reding88759682013-12-12 09:57:53 +0100571
572/**
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000573 * drm_dp_aux_unregister() - unregister an AUX adapter
Thierry Reding88759682013-12-12 09:57:53 +0100574 * @aux: DisplayPort AUX channel
575 */
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000576void drm_dp_aux_unregister(struct drm_dp_aux *aux)
Thierry Reding88759682013-12-12 09:57:53 +0100577{
578 i2c_del_adapter(&aux->ddc);
579}
Dave Airlie4f71d0c2014-06-04 16:02:28 +1000580EXPORT_SYMBOL(drm_dp_aux_unregister);