Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fb_ddc.c
Go to the documentation of this file.
1 /*
2  * drivers/video/fb_ddc.c - DDC/EDID read support.
3  *
4  * Copyright (C) 2006 Dennis Munsie <[email protected]>
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License. See the file COPYING in the main directory of this archive
8  * for more details.
9  */
10 
11 #include <linux/delay.h>
12 #include <linux/device.h>
13 #include <linux/module.h>
14 #include <linux/fb.h>
15 #include <linux/i2c-algo-bit.h>
16 #include <linux/slab.h>
17 
18 #include "edid.h"
19 
20 #define DDC_ADDR 0x50
21 
22 static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
23 {
24  unsigned char start = 0x0;
25  unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
26  struct i2c_msg msgs[] = {
27  {
28  .addr = DDC_ADDR,
29  .flags = 0,
30  .len = 1,
31  .buf = &start,
32  }, {
33  .addr = DDC_ADDR,
34  .flags = I2C_M_RD,
35  .len = EDID_LENGTH,
36  .buf = buf,
37  }
38  };
39 
40  if (!buf) {
41  dev_warn(&adapter->dev, "unable to allocate memory for EDID "
42  "block.\n");
43  return NULL;
44  }
45 
46  if (i2c_transfer(adapter, msgs, 2) == 2)
47  return buf;
48 
49  dev_warn(&adapter->dev, "unable to read EDID block.\n");
50  kfree(buf);
51  return NULL;
52 }
53 
54 unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
55 {
56  struct i2c_algo_bit_data *algo_data = adapter->algo_data;
57  unsigned char *edid = NULL;
58  int i, j;
59 
60  algo_data->setscl(algo_data->data, 1);
61 
62  for (i = 0; i < 3; i++) {
63  /* For some old monitors we need the
64  * following process to initialize/stop DDC
65  */
66  algo_data->setsda(algo_data->data, 1);
67  msleep(13);
68 
69  algo_data->setscl(algo_data->data, 1);
70  for (j = 0; j < 5; j++) {
71  msleep(10);
72  if (algo_data->getscl(algo_data->data))
73  break;
74  }
75  if (j == 5)
76  continue;
77 
78  algo_data->setsda(algo_data->data, 0);
79  msleep(15);
80  algo_data->setscl(algo_data->data, 0);
81  msleep(15);
82  algo_data->setsda(algo_data->data, 1);
83  msleep(15);
84 
85  /* Do the real work */
86  edid = fb_do_probe_ddc_edid(adapter);
87  algo_data->setsda(algo_data->data, 0);
88  algo_data->setscl(algo_data->data, 0);
89  msleep(15);
90 
91  algo_data->setscl(algo_data->data, 1);
92  for (j = 0; j < 10; j++) {
93  msleep(10);
94  if (algo_data->getscl(algo_data->data))
95  break;
96  }
97 
98  algo_data->setsda(algo_data->data, 1);
99  msleep(15);
100  algo_data->setscl(algo_data->data, 0);
101  algo_data->setsda(algo_data->data, 0);
102  if (edid)
103  break;
104  }
105  /* Release the DDC lines when done or the Apple Cinema HD display
106  * will switch off
107  */
108  algo_data->setsda(algo_data->data, 1);
109  algo_data->setscl(algo_data->data, 1);
110 
111  adapter->class |= I2C_CLASS_DDC;
112  return edid;
113 }
114 
116 
117 MODULE_AUTHOR("Dennis Munsie <[email protected]>");
118 MODULE_DESCRIPTION("DDC/EDID reading support");
119 MODULE_LICENSE("GPL");