aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/cyber2000fb.c
diff options
context:
space:
mode:
authorOndrej Zary <linux@rainbow-software.org>2010-08-11 15:48:03 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-02-11 05:15:54 -0500
commite5dedf8d561fb309ba37003546025300678da549 (patch)
tree17f4d94ee08ab3c9dec6cbe81a97186119a389dc /drivers/video/cyber2000fb.c
parentfcd3c7796c62f6bf5300ee52a87b8654084c5ae4 (diff)
VIDEO: cyberpro: add I2C support
Add I2C support for the DDC bus to cyber2000fb driver. This is only bus support, driver does not use EDID. Tested on two different CyberPro 2000 cards with i2cdetect and decode-edid. Signed-off-by: Ondrej Zary <linux@rainbow-software.org> [removed i2c-id.h include - rmk] Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/video/cyber2000fb.c')
-rw-r--r--drivers/video/cyber2000fb.c127
1 files changed, 127 insertions, 0 deletions
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
93static char *default_font = "Acorn8x8"; 102static 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}
1142EXPORT_SYMBOL(cyber2000fb_detach); 1157EXPORT_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
1167static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
1168{
1169 spin_lock(&cfb->reg_b0_lock);
1170 cyber2000fb_writew(0x1bf, 0x3ce, cfb);
1171}
1172
1173static 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
1180static 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
1195static 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
1210static 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
1222static 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
1234static 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
1408failed: 1527failed:
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