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 22static 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 54unsigned 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 115EXPORT_SYMBOL_GPL(fb_ddc_read); 116 117MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>"); 118MODULE_DESCRIPTION("DDC/EDID reading support"); 119MODULE_LICENSE("GPL"); 120