diff options
Diffstat (limited to 'drivers/video/cyber2000fb.c')
-rw-r--r-- | drivers/video/cyber2000fb.c | 122 |
1 files changed, 108 insertions, 14 deletions
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index eeccdb8f4848..27cb3b23c3da 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #include <linux/pci.h> | 47 | #include <linux/pci.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/io.h> | 49 | #include <linux/io.h> |
50 | |||
51 | #include <linux/i2c.h> | 50 | #include <linux/i2c.h> |
52 | #include <linux/i2c-algo-bit.h> | 51 | #include <linux/i2c-algo-bit.h> |
53 | 52 | ||
@@ -99,6 +98,11 @@ struct cfb_info { | |||
99 | struct i2c_adapter ddc_adapter; | 98 | struct i2c_adapter ddc_adapter; |
100 | struct i2c_algo_bit_data ddc_algo; | 99 | struct i2c_algo_bit_data ddc_algo; |
101 | #endif | 100 | #endif |
101 | |||
102 | #ifdef CONFIG_FB_CYBER2000_I2C | ||
103 | struct i2c_adapter i2c_adapter; | ||
104 | struct i2c_algo_bit_data i2c_algo; | ||
105 | #endif | ||
102 | }; | 106 | }; |
103 | 107 | ||
104 | static char *default_font = "Acorn8x8"; | 108 | static char *default_font = "Acorn8x8"; |
@@ -1131,6 +1135,11 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx) | |||
1131 | { | 1135 | { |
1132 | if (int_cfb_info != NULL) { | 1136 | if (int_cfb_info != NULL) { |
1133 | info->dev = int_cfb_info->dev; | 1137 | info->dev = int_cfb_info->dev; |
1138 | #ifdef CONFIG_FB_CYBER2000_I2C | ||
1139 | info->i2c = &int_cfb_info->i2c_adapter; | ||
1140 | #else | ||
1141 | info->i2c = NULL; | ||
1142 | #endif | ||
1134 | info->regs = int_cfb_info->regs; | 1143 | info->regs = int_cfb_info->regs; |
1135 | info->fb = int_cfb_info->fb.screen_base; | 1144 | info->fb = int_cfb_info->fb.screen_base; |
1136 | info->fb_size = int_cfb_info->fb.fix.smem_len; | 1145 | info->fb_size = int_cfb_info->fb.fix.smem_len; |
@@ -1251,6 +1260,86 @@ static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb) | |||
1251 | } | 1260 | } |
1252 | #endif /* CONFIG_FB_CYBER2000_DDC */ | 1261 | #endif /* CONFIG_FB_CYBER2000_DDC */ |
1253 | 1262 | ||
1263 | #ifdef CONFIG_FB_CYBER2000_I2C | ||
1264 | static void cyber2000fb_i2c_setsda(void *data, int state) | ||
1265 | { | ||
1266 | struct cfb_info *cfb = data; | ||
1267 | unsigned int latch2; | ||
1268 | |||
1269 | spin_lock(&cfb->reg_b0_lock); | ||
1270 | latch2 = cyber2000_grphr(EXT_LATCH2, cfb); | ||
1271 | latch2 &= EXT_LATCH2_I2C_CLKEN; | ||
1272 | if (state) | ||
1273 | latch2 |= EXT_LATCH2_I2C_DATEN; | ||
1274 | cyber2000_grphw(EXT_LATCH2, latch2, cfb); | ||
1275 | spin_unlock(&cfb->reg_b0_lock); | ||
1276 | } | ||
1277 | |||
1278 | static void cyber2000fb_i2c_setscl(void *data, int state) | ||
1279 | { | ||
1280 | struct cfb_info *cfb = data; | ||
1281 | unsigned int latch2; | ||
1282 | |||
1283 | spin_lock(&cfb->reg_b0_lock); | ||
1284 | latch2 = cyber2000_grphr(EXT_LATCH2, cfb); | ||
1285 | latch2 &= EXT_LATCH2_I2C_DATEN; | ||
1286 | if (state) | ||
1287 | latch2 |= EXT_LATCH2_I2C_CLKEN; | ||
1288 | cyber2000_grphw(EXT_LATCH2, latch2, cfb); | ||
1289 | spin_unlock(&cfb->reg_b0_lock); | ||
1290 | } | ||
1291 | |||
1292 | static int cyber2000fb_i2c_getsda(void *data) | ||
1293 | { | ||
1294 | struct cfb_info *cfb = data; | ||
1295 | int ret; | ||
1296 | |||
1297 | spin_lock(&cfb->reg_b0_lock); | ||
1298 | ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT); | ||
1299 | spin_unlock(&cfb->reg_b0_lock); | ||
1300 | |||
1301 | return ret; | ||
1302 | } | ||
1303 | |||
1304 | static int cyber2000fb_i2c_getscl(void *data) | ||
1305 | { | ||
1306 | struct cfb_info *cfb = data; | ||
1307 | int ret; | ||
1308 | |||
1309 | spin_lock(&cfb->reg_b0_lock); | ||
1310 | ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK); | ||
1311 | spin_unlock(&cfb->reg_b0_lock); | ||
1312 | |||
1313 | return ret; | ||
1314 | } | ||
1315 | |||
1316 | static int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb) | ||
1317 | { | ||
1318 | strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id, | ||
1319 | sizeof(cfb->i2c_adapter.name)); | ||
1320 | cfb->i2c_adapter.owner = THIS_MODULE; | ||
1321 | cfb->i2c_adapter.algo_data = &cfb->i2c_algo; | ||
1322 | cfb->i2c_adapter.dev.parent = &cfb->dev->dev; | ||
1323 | cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda; | ||
1324 | cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl; | ||
1325 | cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda; | ||
1326 | cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl; | ||
1327 | cfb->i2c_algo.udelay = 5; | ||
1328 | cfb->i2c_algo.timeout = msecs_to_jiffies(100); | ||
1329 | cfb->i2c_algo.data = cfb; | ||
1330 | |||
1331 | return i2c_bit_add_bus(&cfb->i2c_adapter); | ||
1332 | } | ||
1333 | |||
1334 | static void cyber2000fb_i2c_unregister(struct cfb_info *cfb) | ||
1335 | { | ||
1336 | i2c_del_adapter(&cfb->i2c_adapter); | ||
1337 | } | ||
1338 | #else | ||
1339 | #define cyber2000fb_i2c_register(cfb) (0) | ||
1340 | #define cyber2000fb_i2c_unregister(cfb) do { } while (0) | ||
1341 | #endif | ||
1342 | |||
1254 | /* | 1343 | /* |
1255 | * These parameters give | 1344 | * These parameters give |
1256 | * 640x480, hsync 31.5kHz, vsync 60Hz | 1345 | * 640x480, hsync 31.5kHz, vsync 60Hz |
@@ -1520,7 +1609,14 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) | |||
1520 | 1609 | ||
1521 | if (cfb->dev) | 1610 | if (cfb->dev) |
1522 | cfb->fb.device = &cfb->dev->dev; | 1611 | cfb->fb.device = &cfb->dev->dev; |
1612 | |||
1613 | err = cyber2000fb_i2c_register(cfb); | ||
1614 | if (err) | ||
1615 | goto failed; | ||
1616 | |||
1523 | err = register_framebuffer(&cfb->fb); | 1617 | err = register_framebuffer(&cfb->fb); |
1618 | if (err) | ||
1619 | cyber2000fb_i2c_unregister(cfb); | ||
1524 | 1620 | ||
1525 | failed: | 1621 | failed: |
1526 | #ifdef CONFIG_FB_CYBER2000_DDC | 1622 | #ifdef CONFIG_FB_CYBER2000_DDC |
@@ -1530,6 +1626,16 @@ failed: | |||
1530 | return err; | 1626 | return err; |
1531 | } | 1627 | } |
1532 | 1628 | ||
1629 | static void __devexit cyberpro_common_remove(struct cfb_info *cfb) | ||
1630 | { | ||
1631 | unregister_framebuffer(&cfb->fb); | ||
1632 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1633 | if (cfb->ddc_registered) | ||
1634 | i2c_del_adapter(&cfb->ddc_adapter); | ||
1635 | #endif | ||
1636 | cyber2000fb_i2c_unregister(cfb); | ||
1637 | } | ||
1638 | |||
1533 | static void cyberpro_common_resume(struct cfb_info *cfb) | 1639 | static void cyberpro_common_resume(struct cfb_info *cfb) |
1534 | { | 1640 | { |
1535 | cyberpro_init_hw(cfb); | 1641 | cyberpro_init_hw(cfb); |
@@ -1769,19 +1875,7 @@ static void __devexit cyberpro_pci_remove(struct pci_dev *dev) | |||
1769 | struct cfb_info *cfb = pci_get_drvdata(dev); | 1875 | struct cfb_info *cfb = pci_get_drvdata(dev); |
1770 | 1876 | ||
1771 | if (cfb) { | 1877 | if (cfb) { |
1772 | /* | 1878 | cyberpro_common_remove(cfb); |
1773 | * If unregister_framebuffer fails, then | ||
1774 | * we will be leaving hooks that could cause | ||
1775 | * oopsen laying around. | ||
1776 | */ | ||
1777 | if (unregister_framebuffer(&cfb->fb)) | ||
1778 | printk(KERN_WARNING "%s: danger Will Robinson, " | ||
1779 | "danger danger! Oopsen imminent!\n", | ||
1780 | cfb->fb.fix.id); | ||
1781 | #ifdef CONFIG_FB_CYBER2000_DDC | ||
1782 | if (cfb->ddc_registered) | ||
1783 | i2c_del_adapter(&cfb->ddc_adapter); | ||
1784 | #endif | ||
1785 | iounmap(cfb->region); | 1879 | iounmap(cfb->region); |
1786 | cyberpro_free_fb_info(cfb); | 1880 | cyberpro_free_fb_info(cfb); |
1787 | 1881 | ||