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