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/export.h> 14 #include <linux/module.h> 15 #include <linux/fb.h> 16 #include <linux/i2c-algo-bit.h> 17 #include <linux/slab.h> 18 19 #include "../edid.h" 20 21 #define DDC_ADDR 0x50 22 23 static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) 24 { 25 unsigned char start = 0x0; 26 unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); 27 struct i2c_msg msgs[] = { 28 { 29 .addr = DDC_ADDR, 30 .flags = 0, 31 .len = 1, 32 .buf = &start, 33 }, { 34 .addr = DDC_ADDR, 35 .flags = I2C_M_RD, 36 .len = EDID_LENGTH, 37 .buf = buf, 38 } 39 }; 40 41 if (!buf) { 42 dev_warn(&adapter->dev, "unable to allocate memory for EDID " 43 "block.\n"); 44 return NULL; 45 } 46 47 if (i2c_transfer(adapter, msgs, 2) == 2) 48 return buf; 49 50 dev_warn(&adapter->dev, "unable to read EDID block.\n"); 51 kfree(buf); 52 return NULL; 53 } 54 55 unsigned char *fb_ddc_read(struct i2c_adapter *adapter) 56 { 57 struct i2c_algo_bit_data *algo_data = adapter->algo_data; 58 unsigned char *edid = NULL; 59 int i, j; 60 61 algo_data->setscl(algo_data->data, 1); 62 63 for (i = 0; i < 3; i++) { 64 /* For some old monitors we need the 65 * following process to initialize/stop DDC 66 */ 67 algo_data->setsda(algo_data->data, 1); 68 msleep(13); 69 70 algo_data->setscl(algo_data->data, 1); 71 if (algo_data->getscl) { 72 for (j = 0; j < 5; j++) { 73 msleep(10); 74 if (algo_data->getscl(algo_data->data)) 75 break; 76 } 77 if (j == 5) 78 continue; 79 } else { 80 udelay(algo_data->udelay); 81 } 82 83 algo_data->setsda(algo_data->data, 0); 84 msleep(15); 85 algo_data->setscl(algo_data->data, 0); 86 msleep(15); 87 algo_data->setsda(algo_data->data, 1); 88 msleep(15); 89 90 /* Do the real work */ 91 edid = fb_do_probe_ddc_edid(adapter); 92 algo_data->setsda(algo_data->data, 0); 93 algo_data->setscl(algo_data->data, 0); 94 msleep(15); 95 96 algo_data->setscl(algo_data->data, 1); 97 if (algo_data->getscl) { 98 for (j = 0; j < 10; j++) { 99 msleep(10); 100 if (algo_data->getscl(algo_data->data)) 101 break; 102 } 103 } else { 104 udelay(algo_data->udelay); 105 } 106 107 algo_data->setsda(algo_data->data, 1); 108 msleep(15); 109 algo_data->setscl(algo_data->data, 0); 110 algo_data->setsda(algo_data->data, 0); 111 if (edid) 112 break; 113 } 114 /* Release the DDC lines when done or the Apple Cinema HD display 115 * will switch off 116 */ 117 algo_data->setsda(algo_data->data, 1); 118 algo_data->setscl(algo_data->data, 1); 119 120 return edid; 121 } 122 123 EXPORT_SYMBOL_GPL(fb_ddc_read); 124 125 MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>"); 126 MODULE_DESCRIPTION("DDC/EDID reading support"); 127 MODULE_LICENSE("GPL"); 128