127 lines · c
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 Public7 * License. See the file COPYING in the main directory of this archive8 * 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 0x5021 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 the64 * following process to initialize/stop DDC65 */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 display114 * will switch off115 */116 algo_data->setsda(algo_data->data, 1);117 algo_data->setscl(algo_data->data, 1);118 119 return edid;120}121 122EXPORT_SYMBOL_GPL(fb_ddc_read);123 124MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");125MODULE_DESCRIPTION("DDC/EDID reading support");126MODULE_LICENSE("GPL");127