i2c: tegra: Add stub runtime power management
[linux-2.6.git] / drivers / video / cyber2000fb.c
index eeccdb8..8503807 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/io.h>
-
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
@@ -64,10 +63,10 @@ struct cfb_info {
        struct fb_info          fb;
        struct display_switch   *dispsw;
        struct display          *display;
-       struct pci_dev          *dev;
        unsigned char           __iomem *region;
        unsigned char           __iomem *regs;
        u_int                   id;
+       u_int                   irq;
        int                     func_use_count;
        u_long                  ref_ps;
 
@@ -99,6 +98,11 @@ struct cfb_info {
        struct i2c_adapter      ddc_adapter;
        struct i2c_algo_bit_data        ddc_algo;
 #endif
+
+#ifdef CONFIG_FB_CYBER2000_I2C
+       struct i2c_adapter      i2c_adapter;
+       struct i2c_algo_bit_data i2c_algo;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -1118,24 +1122,22 @@ void cyber2000fb_disable_extregs(struct cfb_info *cfb)
 }
 EXPORT_SYMBOL(cyber2000fb_disable_extregs);
 
-void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
-{
-       memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
-}
-EXPORT_SYMBOL(cyber2000fb_get_fb_var);
-
 /*
  * Attach a capture/tv driver to the core CyberX0X0 driver.
  */
 int cyber2000fb_attach(struct cyberpro_info *info, int idx)
 {
        if (int_cfb_info != NULL) {
-               info->dev             = int_cfb_info->dev;
+               info->dev             = int_cfb_info->fb.device;
+#ifdef CONFIG_FB_CYBER2000_I2C
+               info->i2c             = &int_cfb_info->i2c_adapter;
+#else
+               info->i2c             = NULL;
+#endif
                info->regs            = int_cfb_info->regs;
+               info->irq             = int_cfb_info->irq;
                info->fb              = int_cfb_info->fb.screen_base;
                info->fb_size         = int_cfb_info->fb.fix.smem_len;
-               info->enable_extregs  = cyber2000fb_enable_extregs;
-               info->disable_extregs = cyber2000fb_disable_extregs;
                info->info            = int_cfb_info;
 
                strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
@@ -1236,7 +1238,7 @@ static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
        cfb->ddc_adapter.owner          = THIS_MODULE;
        cfb->ddc_adapter.class          = I2C_CLASS_DDC;
        cfb->ddc_adapter.algo_data      = &cfb->ddc_algo;
-       cfb->ddc_adapter.dev.parent     = &cfb->dev->dev;
+       cfb->ddc_adapter.dev.parent     = cfb->fb.device;
        cfb->ddc_algo.setsda            = cyber2000fb_ddc_setsda;
        cfb->ddc_algo.setscl            = cyber2000fb_ddc_setscl;
        cfb->ddc_algo.getsda            = cyber2000fb_ddc_getsda;
@@ -1251,6 +1253,86 @@ static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
 }
 #endif /* CONFIG_FB_CYBER2000_DDC */
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+static void cyber2000fb_i2c_setsda(void *data, int state)
+{
+       struct cfb_info *cfb = data;
+       unsigned int latch2;
+
+       spin_lock(&cfb->reg_b0_lock);
+       latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
+       latch2 &= EXT_LATCH2_I2C_CLKEN;
+       if (state)
+               latch2 |= EXT_LATCH2_I2C_DATEN;
+       cyber2000_grphw(EXT_LATCH2, latch2, cfb);
+       spin_unlock(&cfb->reg_b0_lock);
+}
+
+static void cyber2000fb_i2c_setscl(void *data, int state)
+{
+       struct cfb_info *cfb = data;
+       unsigned int latch2;
+
+       spin_lock(&cfb->reg_b0_lock);
+       latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
+       latch2 &= EXT_LATCH2_I2C_DATEN;
+       if (state)
+               latch2 |= EXT_LATCH2_I2C_CLKEN;
+       cyber2000_grphw(EXT_LATCH2, latch2, cfb);
+       spin_unlock(&cfb->reg_b0_lock);
+}
+
+static int cyber2000fb_i2c_getsda(void *data)
+{
+       struct cfb_info *cfb = data;
+       int ret;
+
+       spin_lock(&cfb->reg_b0_lock);
+       ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT);
+       spin_unlock(&cfb->reg_b0_lock);
+
+       return ret;
+}
+
+static int cyber2000fb_i2c_getscl(void *data)
+{
+       struct cfb_info *cfb = data;
+       int ret;
+
+       spin_lock(&cfb->reg_b0_lock);
+       ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK);
+       spin_unlock(&cfb->reg_b0_lock);
+
+       return ret;
+}
+
+static int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb)
+{
+       strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
+               sizeof(cfb->i2c_adapter.name));
+       cfb->i2c_adapter.owner = THIS_MODULE;
+       cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
+       cfb->i2c_adapter.dev.parent = cfb->fb.device;
+       cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
+       cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl;
+       cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda;
+       cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl;
+       cfb->i2c_algo.udelay = 5;
+       cfb->i2c_algo.timeout = msecs_to_jiffies(100);
+       cfb->i2c_algo.data = cfb;
+
+       return i2c_bit_add_bus(&cfb->i2c_adapter);
+}
+
+static void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
+{
+       i2c_del_adapter(&cfb->i2c_adapter);
+}
+#else
+#define cyber2000fb_i2c_register(cfb)  (0)
+#define cyber2000fb_i2c_unregister(cfb)        do { } while (0)
+#endif
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1518,9 +1600,13 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
                cfb->fb.var.xres, cfb->fb.var.yres,
                h_sync / 1000, h_sync % 1000, v_sync);
 
-       if (cfb->dev)
-               cfb->fb.device = &cfb->dev->dev;
+       err = cyber2000fb_i2c_register(cfb);
+       if (err)
+               goto failed;
+
        err = register_framebuffer(&cfb->fb);
+       if (err)
+               cyber2000fb_i2c_unregister(cfb);
 
 failed:
 #ifdef CONFIG_FB_CYBER2000_DDC
@@ -1530,6 +1616,16 @@ failed:
        return err;
 }
 
+static void __devexit cyberpro_common_remove(struct cfb_info *cfb)
+{
+       unregister_framebuffer(&cfb->fb);
+#ifdef CONFIG_FB_CYBER2000_DDC
+       if (cfb->ddc_registered)
+               i2c_del_adapter(&cfb->ddc_adapter);
+#endif
+       cyber2000fb_i2c_unregister(cfb);
+}
+
 static void cyberpro_common_resume(struct cfb_info *cfb)
 {
        cyberpro_init_hw(cfb);
@@ -1563,12 +1659,13 @@ static int __devinit cyberpro_vl_probe(void)
        if (!cfb)
                goto failed_release;
 
-       cfb->dev = NULL;
+       cfb->irq = -1;
        cfb->region = ioremap(FB_START, FB_SIZE);
        if (!cfb->region)
                goto failed_ioremap;
 
        cfb->regs = cfb->region + MMIO_OFFSET;
+       cfb->fb.device = NULL;
        cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET;
        cfb->fb.fix.smem_start = FB_START;
 
@@ -1706,12 +1803,13 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (err)
                goto failed_regions;
 
-       cfb->dev = dev;
+       cfb->irq = dev->irq;
        cfb->region = pci_ioremap_bar(dev, 0);
        if (!cfb->region)
                goto failed_ioremap;
 
        cfb->regs = cfb->region + MMIO_OFFSET;
+       cfb->fb.device = &dev->dev;
        cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
        cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
 
@@ -1769,19 +1867,7 @@ static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
        struct cfb_info *cfb = pci_get_drvdata(dev);
 
        if (cfb) {
-               /*
-                * If unregister_framebuffer fails, then
-                * we will be leaving hooks that could cause
-                * oopsen laying around.
-                */
-               if (unregister_framebuffer(&cfb->fb))
-                       printk(KERN_WARNING "%s: danger Will Robinson, "
-                               "danger danger!  Oopsen imminent!\n",
-                               cfb->fb.fix.id);
-#ifdef CONFIG_FB_CYBER2000_DDC
-               if (cfb->ddc_registered)
-                       i2c_del_adapter(&cfb->ddc_adapter);
-#endif
+               cyberpro_common_remove(cfb);
                iounmap(cfb->region);
                cyberpro_free_fb_info(cfb);