diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-02 04:57:07 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-02-11 05:16:05 -0500 |
commit | b7ca01a9b20e3fdd11745227905e9ad8a99e0123 (patch) | |
tree | 6d4157e1253e074343044566092bb3de3c950234 /drivers | |
parent | 052a7f5c496b7d2966edea0f576ec39f41703992 (diff) |
VIDEO: cyberpro: add support for video capture I2C
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/cyber2000fb.c | 122 | ||||
-rw-r--r-- | drivers/video/cyber2000fb.h | 1 |
3 files changed, 118 insertions, 14 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e0c7edf6c82b..b20f0f81dc01 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -448,6 +448,15 @@ config FB_CYBER2000_DDC | |||
448 | Say Y here if you want DDC support for your CyberPro graphics | 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. | 449 | card. This is only I2C bus support, driver does not use EDID. |
450 | 450 | ||
451 | config FB_CYBER2000_I2C | ||
452 | bool "CyberPro 2000/2010/5000 I2C support" | ||
453 | depends on FB_CYBER2000 && I2C && ARCH_NETWINDER | ||
454 | select I2C_ALGOBIT | ||
455 | help | ||
456 | Enable support for the I2C video decoder interface on the | ||
457 | Integraphics CyberPro 20x0 and 5000 VGA chips. This is used | ||
458 | on the Netwinder machines for the SAA7111 video capture. | ||
459 | |||
451 | config FB_APOLLO | 460 | config FB_APOLLO |
452 | bool | 461 | bool |
453 | depends on (FB = y) && APOLLO | 462 | depends on (FB = y) && APOLLO |
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 | ||
diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h index de4fc43e51c1..814cce5acf12 100644 --- a/drivers/video/cyber2000fb.h +++ b/drivers/video/cyber2000fb.h | |||
@@ -465,6 +465,7 @@ struct cfb_info; | |||
465 | 465 | ||
466 | struct cyberpro_info { | 466 | struct cyberpro_info { |
467 | struct pci_dev *dev; | 467 | struct pci_dev *dev; |
468 | struct i2c_adapter *i2c; | ||
468 | unsigned char __iomem *regs; | 469 | unsigned char __iomem *regs; |
469 | char __iomem *fb; | 470 | char __iomem *fb; |
470 | char dev_name[32]; | 471 | char dev_name[32]; |