Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * drivers/video/fb_ddc.c - DDC/EDID read support.
0003  *
0004  *  Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
0005  *
0006  * This file is subject to the terms and conditions of the GNU General Public
0007  * License.  See the file COPYING in the main directory of this archive
0008  * for more details.
0009  */
0010 
0011 #include <linux/delay.h>
0012 #include <linux/device.h>
0013 #include <linux/module.h>
0014 #include <linux/fb.h>
0015 #include <linux/i2c-algo-bit.h>
0016 #include <linux/slab.h>
0017 
0018 #include "../edid.h"
0019 
0020 #define DDC_ADDR    0x50
0021 
0022 static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
0023 {
0024     unsigned char start = 0x0;
0025     unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
0026     struct i2c_msg msgs[] = {
0027         {
0028             .addr   = DDC_ADDR,
0029             .flags  = 0,
0030             .len    = 1,
0031             .buf    = &start,
0032         }, {
0033             .addr   = DDC_ADDR,
0034             .flags  = I2C_M_RD,
0035             .len    = EDID_LENGTH,
0036             .buf    = buf,
0037         }
0038     };
0039 
0040     if (!buf) {
0041         dev_warn(&adapter->dev, "unable to allocate memory for EDID "
0042              "block.\n");
0043         return NULL;
0044     }
0045 
0046     if (i2c_transfer(adapter, msgs, 2) == 2)
0047         return buf;
0048 
0049     dev_warn(&adapter->dev, "unable to read EDID block.\n");
0050     kfree(buf);
0051     return NULL;
0052 }
0053 
0054 unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
0055 {
0056     struct i2c_algo_bit_data *algo_data = adapter->algo_data;
0057     unsigned char *edid = NULL;
0058     int i, j;
0059 
0060     algo_data->setscl(algo_data->data, 1);
0061 
0062     for (i = 0; i < 3; i++) {
0063         /* For some old monitors we need the
0064          * following process to initialize/stop DDC
0065          */
0066         algo_data->setsda(algo_data->data, 1);
0067         msleep(13);
0068 
0069         algo_data->setscl(algo_data->data, 1);
0070         if (algo_data->getscl) {
0071             for (j = 0; j < 5; j++) {
0072                 msleep(10);
0073                 if (algo_data->getscl(algo_data->data))
0074                     break;
0075             }
0076             if (j == 5)
0077                 continue;
0078         } else {
0079             udelay(algo_data->udelay);
0080         }
0081 
0082         algo_data->setsda(algo_data->data, 0);
0083         msleep(15);
0084         algo_data->setscl(algo_data->data, 0);
0085         msleep(15);
0086         algo_data->setsda(algo_data->data, 1);
0087         msleep(15);
0088 
0089         /* Do the real work */
0090         edid = fb_do_probe_ddc_edid(adapter);
0091         algo_data->setsda(algo_data->data, 0);
0092         algo_data->setscl(algo_data->data, 0);
0093         msleep(15);
0094 
0095         algo_data->setscl(algo_data->data, 1);
0096         if (algo_data->getscl) {
0097             for (j = 0; j < 10; j++) {
0098                 msleep(10);
0099                 if (algo_data->getscl(algo_data->data))
0100                     break;
0101             }
0102         } else {
0103             udelay(algo_data->udelay);
0104         }
0105 
0106         algo_data->setsda(algo_data->data, 1);
0107         msleep(15);
0108         algo_data->setscl(algo_data->data, 0);
0109         algo_data->setsda(algo_data->data, 0);
0110         if (edid)
0111             break;
0112     }
0113     /* Release the DDC lines when done or the Apple Cinema HD display
0114      * will switch off
0115      */
0116     algo_data->setsda(algo_data->data, 1);
0117     algo_data->setscl(algo_data->data, 1);
0118 
0119     adapter->class |= I2C_CLASS_DDC;
0120     return edid;
0121 }
0122 
0123 EXPORT_SYMBOL_GPL(fb_ddc_read);
0124 
0125 MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
0126 MODULE_DESCRIPTION("DDC/EDID reading support");
0127 MODULE_LICENSE("GPL");