diff options
| author | Dennis Munsie <dmunsie@cecropia.com> | 2006-10-03 04:14:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 11:04:09 -0400 |
| commit | fc5891c8a3ba284f13994d7bc1f1bfa8283982de (patch) | |
| tree | a9361f04236b60e0c1a8b1158e490b505c0961f4 | |
| parent | 66cf75121b1c8128ef9ab2d772c5654ae00c4284 (diff) | |
[PATCH] fbdev: Add generic ddc read functionality
Adds functionality to read the EDID information over the DDC bus in a generic
way. This code is based on the DDC implementation in the radeon driver.
[adaplas]
- separate from fbmon.c and place in new file fb_ddc.c
- remove dependency to CONFIG_I2C and CONFIG_I2C_ALGOBIT, otherwise, feature
will not compile if i2c support is compiled as a module
- feature is selectable only by drivers needing it. It must have a
'select FB_DDC if xxx' in Kconfig
- change printk's to dev_*, the i2c people prefers it
Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/video/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/video/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/fb_ddc.c | 116 | ||||
| -rw-r--r-- | include/linux/fb.h | 2 |
4 files changed, 124 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 652d202adf..d498e908f4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
| @@ -53,6 +53,11 @@ config FB | |||
| 53 | (e.g. an accelerated X server) and that are not frame buffer | 53 | (e.g. an accelerated X server) and that are not frame buffer |
| 54 | device-aware may cause unexpected results. If unsure, say N. | 54 | device-aware may cause unexpected results. If unsure, say N. |
| 55 | 55 | ||
| 56 | config FB_DDC | ||
| 57 | tristate | ||
| 58 | depends on FB && I2C && I2C_ALGOBIT | ||
| 59 | default n | ||
| 60 | |||
| 56 | config FB_CFB_FILLRECT | 61 | config FB_CFB_FILLRECT |
| 57 | tristate | 62 | tristate |
| 58 | depends on FB | 63 | depends on FB |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 481c6c9695..a6980e9a24 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
| @@ -18,6 +18,7 @@ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | |||
| 18 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 18 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
| 19 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o | 19 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o |
| 20 | obj-$(CONFIG_FB_MACMODES) += macmodes.o | 20 | obj-$(CONFIG_FB_MACMODES) += macmodes.o |
| 21 | obj-$(CONFIG_FB_DDC) += fb_ddc.o | ||
| 21 | 22 | ||
| 22 | # Hardware specific drivers go first | 23 | # Hardware specific drivers go first |
| 23 | obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o | 24 | obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o |
diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c new file mode 100644 index 0000000000..3aa6ebf68f --- /dev/null +++ b/drivers/video/fb_ddc.c | |||
| @@ -0,0 +1,116 @@ | |||
| 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 | |||
| 20 | static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) | ||
| 21 | { | ||
| 22 | unsigned char start = 0x0; | ||
| 23 | struct i2c_msg msgs[] = { | ||
| 24 | { | ||
| 25 | .addr = DDC_ADDR, | ||
| 26 | .len = 1, | ||
| 27 | .buf = &start, | ||
| 28 | }, { | ||
| 29 | .addr = DDC_ADDR, | ||
| 30 | .flags = I2C_M_RD, | ||
| 31 | .len = EDID_LENGTH, | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | unsigned char *buf; | ||
| 35 | |||
| 36 | buf = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
| 37 | if (!buf) { | ||
| 38 | dev_warn(&adapter->dev, "unable to allocate memory for EDID " | ||
| 39 | "block.\n"); | ||
| 40 | return NULL; | ||
| 41 | } | ||
| 42 | msgs[1].buf = buf; | ||
| 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 | |||
| 52 | unsigned 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 | algo_data->setscl(algo_data->data, 0); | ||
| 60 | |||
| 61 | for (i = 0; i < 3; i++) { | ||
| 62 | /* For some old monitors we need the | ||
| 63 | * following process to initialize/stop DDC | ||
| 64 | */ | ||
| 65 | algo_data->setsda(algo_data->data, 0); | ||
| 66 | msleep(13); | ||
| 67 | |||
| 68 | algo_data->setscl(algo_data->data, 1); | ||
| 69 | for (j = 0; j < 5; j++) { | ||
| 70 | msleep(10); | ||
| 71 | if (algo_data->getscl(algo_data->data)) | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | if (j == 5) | ||
| 75 | continue; | ||
| 76 | |||
| 77 | algo_data->setsda(algo_data->data, 0); | ||
| 78 | msleep(15); | ||
| 79 | algo_data->setscl(algo_data->data, 0); | ||
| 80 | msleep(15); | ||
| 81 | algo_data->setsda(algo_data->data, 1); | ||
| 82 | msleep(15); | ||
| 83 | |||
| 84 | /* Do the real work */ | ||
| 85 | edid = fb_do_probe_ddc_edid(adapter); | ||
| 86 | algo_data->setsda(algo_data->data, 0); | ||
| 87 | algo_data->setscl(algo_data->data, 0); | ||
| 88 | msleep(15); | ||
| 89 | |||
| 90 | algo_data->setscl(algo_data->data, 1); | ||
| 91 | for (j = 0; j < 10; j++) { | ||
| 92 | msleep(10); | ||
| 93 | if (algo_data->getscl(algo_data->data)) | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | |||
| 97 | algo_data->setsda(algo_data->data, 1); | ||
| 98 | msleep(15); | ||
| 99 | algo_data->setscl(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, 0); | ||
| 107 | algo_data->setscl(algo_data->data, 0); | ||
| 108 | |||
| 109 | return edid; | ||
| 110 | } | ||
| 111 | |||
| 112 | EXPORT_SYMBOL_GPL(fb_ddc_read); | ||
| 113 | |||
| 114 | MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>"); | ||
| 115 | MODULE_DESCRIPTION("DDC/EDID reading support"); | ||
| 116 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/fb.h b/include/linux/fb.h index 2f335e9660..37aab314f0 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define _LINUX_FB_H | 2 | #define _LINUX_FB_H |
| 3 | 3 | ||
| 4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
| 5 | #include <linux/i2c.h> | ||
| 5 | 6 | ||
| 6 | /* Definitions of frame buffers */ | 7 | /* Definitions of frame buffers */ |
| 7 | 8 | ||
| @@ -940,6 +941,7 @@ extern void fb_edid_to_monspecs(unsigned char *edid, | |||
| 940 | struct fb_monspecs *specs); | 941 | struct fb_monspecs *specs); |
| 941 | extern void fb_destroy_modedb(struct fb_videomode *modedb); | 942 | extern void fb_destroy_modedb(struct fb_videomode *modedb); |
| 942 | extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); | 943 | extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); |
| 944 | extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); | ||
| 943 | 945 | ||
| 944 | /* drivers/video/modedb.c */ | 946 | /* drivers/video/modedb.c */ |
| 945 | #define VESA_MODEDB_SIZE 34 | 947 | #define VESA_MODEDB_SIZE 34 |
