1 /* 2 * drivers/video/fb_ddc.c - DDC/EDID read support. 3 * 4 * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> 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 if (algo_data->getscl) { 71 for (j = 0; j < 5; j++) { 72 msleep(10); 73 if (algo_data->getscl(algo_data->data)) 74 break; 75 } 76 if (j == 5) 77 continue; 78 } else { 79 udelay(algo_data->udelay); 80 } 81 82 algo_data->setsda(algo_data->data, 0); 83 msleep(15); 84 algo_data->setscl(algo_data->data, 0); 85 msleep(15); 86 algo_data->setsda(algo_data->data, 1); 87 msleep(15); 88 89 /* Do the real work */ 90 edid = fb_do_probe_ddc_edid(adapter); 91 algo_data->setsda(algo_data->data, 0); 92 algo_data->setscl(algo_data->data, 0); 93 msleep(15); 94 95 algo_data->setscl(algo_data->data, 1); 96 if (algo_data->getscl) { 97 for (j = 0; j < 10; j++) { 98 msleep(10); 99 if (algo_data->getscl(algo_data->data)) 100 break; 101 } 102 } else { 103 udelay(algo_data->udelay); 104 } 105 106 algo_data->setsda(algo_data->data, 1); 107 msleep(15); 108 algo_data->setscl(algo_data->data, 0); 109 algo_data->setsda(algo_data->data, 0); 110 if (edid) 111 break; 112 } 113 /* Release the DDC lines when done or the Apple Cinema HD display 114 * will switch off 115 */ 116 algo_data->setsda(algo_data->data, 1); 117 algo_data->setscl(algo_data->data, 1); 118 119 return edid; 120 } 121 122 EXPORT_SYMBOL_GPL(fb_ddc_read); 123 124 MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>"); 125 MODULE_DESCRIPTION("DDC/EDID reading support"); 126 MODULE_LICENSE("GPL"); 127