diff options
-rw-r--r-- | drivers/video/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/cyber2000fb.c | 127 |
2 files changed, 136 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6bafb51bb437..e0c7edf6c82b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -439,6 +439,15 @@ config FB_CYBER2000 | |||
439 | Say Y if you have a NetWinder or a graphics card containing this | 439 | Say Y if you have a NetWinder or a graphics card containing this |
440 | device, otherwise say N. | 440 | device, otherwise say N. |
441 | 441 | ||
442 | config FB_CYBER2000_DDC | ||
443 | bool "DDC for CyberPro support" | ||
444 | depends on FB_CYBER2000 | ||
445 | select FB_DDC | ||
446 | default y | ||
447 | help | ||
448 | Say Y here if you want DDC support for your CyberPro graphics | ||
449 | card. This is only I2C bus support, driver does not use EDID. | ||
450 | |||
442 | config FB_APOLLO | 451 | config FB_APOLLO |
443 | bool | 452 | bool |
444 | depends on (FB = y) && APOLLO | 453 | depends on (FB = y) && APOLLO |
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index e946741ba2ed..87d2aafa92fe 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -48,6 +48,9 @@ | |||
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/io.h> | 49 | #include <linux/io.h> |
50 | 50 | ||
51 | #include <linux/i2c.h> | ||
52 | #include <linux/i2c-algo-bit.h> | ||
53 | |||
51 | #include <asm/pgtable.h> | 54 | #include <asm/pgtable.h> |
52 | #include <asm/system.h> | 55 | #include <asm/system.h> |
53 | 56 | ||
@@ -88,6 +91,12 @@ struct cfb_info { | |||
88 | u_char ramdac_powerdown; | 91 | u_char ramdac_powerdown; |
89 | 92 | ||
90 | u32 pseudo_palette[16]; | 93 | u32 pseudo_palette[16]; |
94 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
95 | bool ddc_registered; | ||
96 | struct i2c_adapter ddc_adapter; | ||
97 | struct i2c_algo_bit_data ddc_algo; | ||
98 | spinlock_t reg_b0_lock; | ||
99 | #endif | ||
91 | }; | 100 | }; |
92 | 101 | ||
93 | static char *default_font = "Acorn8x8"; | 102 | static char *default_font = "Acorn8x8"; |
@@ -494,6 +503,9 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) | |||
494 | cyber2000_attrw(0x14, 0x00, cfb); | 503 | cyber2000_attrw(0x14, 0x00, cfb); |
495 | 504 | ||
496 | /* PLL registers */ | 505 | /* PLL registers */ |
506 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
507 | spin_lock(&cfb->reg_b0_lock); | ||
508 | #endif | ||
497 | cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); | 509 | cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); |
498 | cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); | 510 | cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); |
499 | cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); | 511 | cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); |
@@ -501,6 +513,9 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) | |||
501 | cyber2000_grphw(0x90, 0x01, cfb); | 513 | cyber2000_grphw(0x90, 0x01, cfb); |
502 | cyber2000_grphw(0xb9, 0x80, cfb); | 514 | cyber2000_grphw(0xb9, 0x80, cfb); |
503 | cyber2000_grphw(0xb9, 0x00, cfb); | 515 | cyber2000_grphw(0xb9, 0x00, cfb); |
516 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
517 | spin_unlock(&cfb->reg_b0_lock); | ||
518 | #endif | ||
504 | 519 | ||
505 | cfb->ramdac_ctrl = hw->ramdac; | 520 | cfb->ramdac_ctrl = hw->ramdac; |
506 | cyber2000fb_write_ramdac_ctrl(cfb); | 521 | cyber2000fb_write_ramdac_ctrl(cfb); |
@@ -1141,6 +1156,105 @@ void cyber2000fb_detach(int idx) | |||
1141 | } | 1156 | } |
1142 | EXPORT_SYMBOL(cyber2000fb_detach); | 1157 | EXPORT_SYMBOL(cyber2000fb_detach); |
1143 | 1158 | ||
1159 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1160 | |||
1161 | #define DDC_REG 0xb0 | ||
1162 | #define DDC_SCL_OUT (1 << 0) | ||
1163 | #define DDC_SDA_OUT (1 << 4) | ||
1164 | #define DDC_SCL_IN (1 << 2) | ||
1165 | #define DDC_SDA_IN (1 << 6) | ||
1166 | |||
1167 | static void cyber2000fb_enable_ddc(struct cfb_info *cfb) | ||
1168 | { | ||
1169 | spin_lock(&cfb->reg_b0_lock); | ||
1170 | cyber2000fb_writew(0x1bf, 0x3ce, cfb); | ||
1171 | } | ||
1172 | |||
1173 | static void cyber2000fb_disable_ddc(struct cfb_info *cfb) | ||
1174 | { | ||
1175 | cyber2000fb_writew(0x0bf, 0x3ce, cfb); | ||
1176 | spin_unlock(&cfb->reg_b0_lock); | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | static void cyber2000fb_ddc_setscl(void *data, int val) | ||
1181 | { | ||
1182 | struct cfb_info *cfb = data; | ||
1183 | unsigned char reg; | ||
1184 | |||
1185 | cyber2000fb_enable_ddc(cfb); | ||
1186 | reg = cyber2000_grphr(DDC_REG, cfb); | ||
1187 | if (!val) /* bit is inverted */ | ||
1188 | reg |= DDC_SCL_OUT; | ||
1189 | else | ||
1190 | reg &= ~DDC_SCL_OUT; | ||
1191 | cyber2000_grphw(DDC_REG, reg, cfb); | ||
1192 | cyber2000fb_disable_ddc(cfb); | ||
1193 | } | ||
1194 | |||
1195 | static void cyber2000fb_ddc_setsda(void *data, int val) | ||
1196 | { | ||
1197 | struct cfb_info *cfb = data; | ||
1198 | unsigned char reg; | ||
1199 | |||
1200 | cyber2000fb_enable_ddc(cfb); | ||
1201 | reg = cyber2000_grphr(DDC_REG, cfb); | ||
1202 | if (!val) /* bit is inverted */ | ||
1203 | reg |= DDC_SDA_OUT; | ||
1204 | else | ||
1205 | reg &= ~DDC_SDA_OUT; | ||
1206 | cyber2000_grphw(DDC_REG, reg, cfb); | ||
1207 | cyber2000fb_disable_ddc(cfb); | ||
1208 | } | ||
1209 | |||
1210 | static int cyber2000fb_ddc_getscl(void *data) | ||
1211 | { | ||
1212 | struct cfb_info *cfb = data; | ||
1213 | int retval; | ||
1214 | |||
1215 | cyber2000fb_enable_ddc(cfb); | ||
1216 | retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN); | ||
1217 | cyber2000fb_disable_ddc(cfb); | ||
1218 | |||
1219 | return retval; | ||
1220 | } | ||
1221 | |||
1222 | static int cyber2000fb_ddc_getsda(void *data) | ||
1223 | { | ||
1224 | struct cfb_info *cfb = data; | ||
1225 | int retval; | ||
1226 | |||
1227 | cyber2000fb_enable_ddc(cfb); | ||
1228 | retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN); | ||
1229 | cyber2000fb_disable_ddc(cfb); | ||
1230 | |||
1231 | return retval; | ||
1232 | } | ||
1233 | |||
1234 | static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb) | ||
1235 | { | ||
1236 | spin_lock_init(&cfb->reg_b0_lock); | ||
1237 | |||
1238 | strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id, | ||
1239 | sizeof(cfb->ddc_adapter.name)); | ||
1240 | cfb->ddc_adapter.owner = THIS_MODULE; | ||
1241 | cfb->ddc_adapter.class = I2C_CLASS_DDC; | ||
1242 | cfb->ddc_adapter.algo_data = &cfb->ddc_algo; | ||
1243 | cfb->ddc_adapter.dev.parent = &cfb->dev->dev; | ||
1244 | cfb->ddc_algo.setsda = cyber2000fb_ddc_setsda; | ||
1245 | cfb->ddc_algo.setscl = cyber2000fb_ddc_setscl; | ||
1246 | cfb->ddc_algo.getsda = cyber2000fb_ddc_getsda; | ||
1247 | cfb->ddc_algo.getscl = cyber2000fb_ddc_getscl; | ||
1248 | cfb->ddc_algo.udelay = 10; | ||
1249 | cfb->ddc_algo.timeout = 20; | ||
1250 | cfb->ddc_algo.data = cfb; | ||
1251 | |||
1252 | i2c_set_adapdata(&cfb->ddc_adapter, cfb); | ||
1253 | |||
1254 | return i2c_bit_add_bus(&cfb->ddc_adapter); | ||
1255 | } | ||
1256 | #endif /* CONFIG_FB_CYBER2000_DDC */ | ||
1257 | |||
1144 | /* | 1258 | /* |
1145 | * These parameters give | 1259 | * These parameters give |
1146 | * 640x480, hsync 31.5kHz, vsync 60Hz | 1260 | * 640x480, hsync 31.5kHz, vsync 60Hz |
@@ -1369,6 +1483,11 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) | |||
1369 | cfb->fb.fix.mmio_len = MMIO_SIZE; | 1483 | cfb->fb.fix.mmio_len = MMIO_SIZE; |
1370 | cfb->fb.screen_base = cfb->region; | 1484 | cfb->fb.screen_base = cfb->region; |
1371 | 1485 | ||
1486 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1487 | if (cyber2000fb_setup_ddc_bus(cfb) == 0) | ||
1488 | cfb->ddc_registered = true; | ||
1489 | #endif | ||
1490 | |||
1372 | err = -EINVAL; | 1491 | err = -EINVAL; |
1373 | if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, | 1492 | if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, |
1374 | &cyber2000fb_default_mode, 8)) { | 1493 | &cyber2000fb_default_mode, 8)) { |
@@ -1406,6 +1525,10 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) | |||
1406 | err = register_framebuffer(&cfb->fb); | 1525 | err = register_framebuffer(&cfb->fb); |
1407 | 1526 | ||
1408 | failed: | 1527 | failed: |
1528 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1529 | if (err && cfb->ddc_registered) | ||
1530 | i2c_del_adapter(&cfb->ddc_adapter); | ||
1531 | #endif | ||
1409 | return err; | 1532 | return err; |
1410 | } | 1533 | } |
1411 | 1534 | ||
@@ -1657,6 +1780,10 @@ static void __devexit cyberpro_pci_remove(struct pci_dev *dev) | |||
1657 | printk(KERN_WARNING "%s: danger Will Robinson, " | 1780 | printk(KERN_WARNING "%s: danger Will Robinson, " |
1658 | "danger danger! Oopsen imminent!\n", | 1781 | "danger danger! Oopsen imminent!\n", |
1659 | cfb->fb.fix.id); | 1782 | cfb->fb.fix.id); |
1783 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1784 | if (cfb->ddc_registered) | ||
1785 | i2c_del_adapter(&cfb->ddc_adapter); | ||
1786 | #endif | ||
1660 | iounmap(cfb->region); | 1787 | iounmap(cfb->region); |
1661 | cyberpro_free_fb_info(cfb); | 1788 | cyberpro_free_fb_info(cfb); |
1662 | 1789 | ||