All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] cyber2000fb: add I2C support
@ 2010-07-31 20:55 ` Ondrej Zary
  0 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-07-31 20:55 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-07-31 22:49:55.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,11 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_I2C
+	bool			i2c_registered;
+	struct i2c_adapter	i2c_adapter;
+	struct i2c_algo_bit_data	i2c_algo;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -1145,6 +1154,95 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(char enable, struct cfb_info *cfb)
+{
+	cyber2000fb_writew(((enable & 0x01) << 8) | 0xbf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_enable_ddc(0, cfb);
+}
+
+static void cyber2000fb_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_enable_ddc(0, cfb);
+}
+
+static int cyber2000fb_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_enable_ddc(0, cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_enable_ddc(0, cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(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.class		= I2C_CLASS_DDC;
+	cfb->i2c_adapter.algo_data	= &cfb->i2c_algo;
+	cfb->i2c_adapter.dev.parent	= &cfb->dev->dev;
+	cfb->i2c_algo.setsda		= cyber2000fb_setsda;
+	cfb->i2c_algo.setscl		= cyber2000fb_setscl;
+	cfb->i2c_algo.getsda		= cyber2000fb_getsda;
+	cfb->i2c_algo.getscl		= cyber2000fb_getscl;
+	cfb->i2c_algo.udelay		= 10;
+	cfb->i2c_algo.timeout		= 20;
+	cfb->i2c_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->i2c_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->i2c_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_I2C */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1471,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (cyber2000fb_setup_ddc_bus(cfb) == 0)
+		cfb->i2c_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1513,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (err && cfb->i2c_registered)
+		i2c_del_adapter(&cfb->i2c_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1768,10 @@ static void __devexit cyberpro_pci_remov
 			printk(KERN_WARNING "%s: danger Will Robinson, "
 				"danger danger!  Oopsen imminent!\n",
 				cfb->fb.fix.id);
+#ifdef CONFIG_FB_CYBER2000_I2C
+		if (cfb->i2c_registered)
+			i2c_del_adapter(&cfb->i2c_adapter);
+#endif
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-07-31 22:52:11.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_I2C
+	bool "DDC/I2C for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3] cyber2000fb: add I2C support
@ 2010-07-31 20:55 ` Ondrej Zary
  0 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-07-31 20:55 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-07-31 22:49:55.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,11 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_I2C
+	bool			i2c_registered;
+	struct i2c_adapter	i2c_adapter;
+	struct i2c_algo_bit_data	i2c_algo;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -1145,6 +1154,95 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(char enable, struct cfb_info *cfb)
+{
+	cyber2000fb_writew(((enable & 0x01) << 8) | 0xbf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_enable_ddc(0, cfb);
+}
+
+static void cyber2000fb_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_enable_ddc(0, cfb);
+}
+
+static int cyber2000fb_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_enable_ddc(0, cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(1, cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_enable_ddc(0, cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(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.class		= I2C_CLASS_DDC;
+	cfb->i2c_adapter.algo_data	= &cfb->i2c_algo;
+	cfb->i2c_adapter.dev.parent	= &cfb->dev->dev;
+	cfb->i2c_algo.setsda		= cyber2000fb_setsda;
+	cfb->i2c_algo.setscl		= cyber2000fb_setscl;
+	cfb->i2c_algo.getsda		= cyber2000fb_getsda;
+	cfb->i2c_algo.getscl		= cyber2000fb_getscl;
+	cfb->i2c_algo.udelay		= 10;
+	cfb->i2c_algo.timeout		= 20;
+	cfb->i2c_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->i2c_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->i2c_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_I2C */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1471,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (cyber2000fb_setup_ddc_bus(cfb) = 0)
+		cfb->i2c_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1513,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (err && cfb->i2c_registered)
+		i2c_del_adapter(&cfb->i2c_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1768,10 @@ static void __devexit cyberpro_pci_remov
 			printk(KERN_WARNING "%s: danger Will Robinson, "
 				"danger danger!  Oopsen imminent!\n",
 				cfb->fb.fix.id);
+#ifdef CONFIG_FB_CYBER2000_I2C
+		if (cfb->i2c_registered)
+			i2c_del_adapter(&cfb->i2c_adapter);
+#endif
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-07-31 22:52:11.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_I2C
+	bool "DDC/I2C for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] cyber2000fb: add I2C support
  2010-07-31 20:55 ` Ondrej Zary
@ 2010-07-31 21:42   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 10+ messages in thread
From: Russell King - ARM Linux @ 2010-07-31 21:42 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: linux-fbdev, Kernel development list

On Sat, Jul 31, 2010 at 10:55:49PM +0200, Ondrej Zary wrote:
> 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.

I'm debating a bit about this.

One thing I'm concerned about is switching the DCLK registers to DCC
mode without any protection against mode changes co-inciding with
I2C activity.  On a SMP machine, it's possible for both to happen
simultaneously.

Secondly, please name these I2C bits with 'ddc' in the name - the
CyberPro appear to have more than one I2C bus on them (or can have)
such as for driving SAA7111 video decoders.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] cyber2000fb: add I2C support
@ 2010-07-31 21:42   ` Russell King - ARM Linux
  0 siblings, 0 replies; 10+ messages in thread
From: Russell King - ARM Linux @ 2010-07-31 21:42 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: linux-fbdev, Kernel development list

On Sat, Jul 31, 2010 at 10:55:49PM +0200, Ondrej Zary wrote:
> 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.

I'm debating a bit about this.

One thing I'm concerned about is switching the DCLK registers to DCC
mode without any protection against mode changes co-inciding with
I2C activity.  On a SMP machine, it's possible for both to happen
simultaneously.

Secondly, please name these I2C bits with 'ddc' in the name - the
CyberPro appear to have more than one I2C bus on them (or can have)
such as for driving SAA7111 video decoders.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3 v2] cyber2000fb: add I2C support
  2010-07-31 21:42   ` Russell King - ARM Linux
@ 2010-07-31 22:13     ` Ondrej Zary
  -1 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-07-31 22:13 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>
---
This is v2 with added locking and ddc things properly named.

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 00:02:59.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,12 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_I2C
+	bool			ddc_registered;
+	struct i2c_adapter	ddc_adapter;
+	struct i2c_algo_bit_data	ddc_algo;
+	struct mutex		reg_b0_lock;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -498,6 +508,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_attrw(0x14, 0x00, cfb);
 
 	/* PLL registers */
+#ifdef CONFIG_FB_CYBER2000_I2C
+	mutex_lock(&cfb->reg_b0_lock);
+#endif
 	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
 	cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
 	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
@@ -505,6 +518,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_grphw(0x90, 0x01, cfb);
 	cyber2000_grphw(0xb9, 0x80, cfb);
 	cyber2000_grphw(0xb9, 0x00, cfb);
+#ifdef CONFIG_FB_CYBER2000_I2C
+	mutex_unlock(&cfb->reg_b0_lock);
+#endif
 
 	cfb->ramdac_ctrl = hw->ramdac;
 	cyber2000fb_write_ramdac_ctrl(cfb);
@@ -1145,6 +1161,105 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
+{
+	mutex_lock(&cfb->reg_b0_lock);
+	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
+{
+	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
+	mutex_unlock(&cfb->reg_b0_lock);
+}
+
+
+static void cyber2000fb_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static void cyber2000fb_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static int cyber2000fb_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+{
+	mutex_init(&cfb->reg_b0_lock);
+
+	strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+		sizeof(cfb->ddc_adapter.name));
+	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_algo.setsda		= cyber2000fb_setsda;
+	cfb->ddc_algo.setscl		= cyber2000fb_setscl;
+	cfb->ddc_algo.getsda		= cyber2000fb_getsda;
+	cfb->ddc_algo.getscl		= cyber2000fb_getscl;
+	cfb->ddc_algo.udelay		= 10;
+	cfb->ddc_algo.timeout		= 20;
+	cfb->ddc_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->ddc_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->ddc_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_I2C */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1488,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (cyber2000fb_setup_ddc_bus(cfb) == 0)
+		cfb->ddc_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1530,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (err && cfb->ddc_registered)
+		i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1785,10 @@ static void __devexit cyberpro_pci_remov
 			printk(KERN_WARNING "%s: danger Will Robinson, "
 				"danger danger!  Oopsen imminent!\n",
 				cfb->fb.fix.id);
+#ifdef CONFIG_FB_CYBER2000_I2C
+		if (cfb->ddc_registered)
+			i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-07-31 22:54:13.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_I2C
+	bool "DDC/I2C for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3 v2] cyber2000fb: add I2C support
@ 2010-07-31 22:13     ` Ondrej Zary
  0 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-07-31 22:13 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>
---
This is v2 with added locking and ddc things properly named.

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 00:02:59.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,12 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_I2C
+	bool			ddc_registered;
+	struct i2c_adapter	ddc_adapter;
+	struct i2c_algo_bit_data	ddc_algo;
+	struct mutex		reg_b0_lock;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -498,6 +508,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_attrw(0x14, 0x00, cfb);
 
 	/* PLL registers */
+#ifdef CONFIG_FB_CYBER2000_I2C
+	mutex_lock(&cfb->reg_b0_lock);
+#endif
 	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
 	cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
 	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
@@ -505,6 +518,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_grphw(0x90, 0x01, cfb);
 	cyber2000_grphw(0xb9, 0x80, cfb);
 	cyber2000_grphw(0xb9, 0x00, cfb);
+#ifdef CONFIG_FB_CYBER2000_I2C
+	mutex_unlock(&cfb->reg_b0_lock);
+#endif
 
 	cfb->ramdac_ctrl = hw->ramdac;
 	cyber2000fb_write_ramdac_ctrl(cfb);
@@ -1145,6 +1161,105 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
+{
+	mutex_lock(&cfb->reg_b0_lock);
+	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
+{
+	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
+	mutex_unlock(&cfb->reg_b0_lock);
+}
+
+
+static void cyber2000fb_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static void cyber2000fb_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static int cyber2000fb_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+{
+	mutex_init(&cfb->reg_b0_lock);
+
+	strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+		sizeof(cfb->ddc_adapter.name));
+	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_algo.setsda		= cyber2000fb_setsda;
+	cfb->ddc_algo.setscl		= cyber2000fb_setscl;
+	cfb->ddc_algo.getsda		= cyber2000fb_getsda;
+	cfb->ddc_algo.getscl		= cyber2000fb_getscl;
+	cfb->ddc_algo.udelay		= 10;
+	cfb->ddc_algo.timeout		= 20;
+	cfb->ddc_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->ddc_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->ddc_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_I2C */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1488,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (cyber2000fb_setup_ddc_bus(cfb) = 0)
+		cfb->ddc_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1530,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_I2C
+	if (err && cfb->ddc_registered)
+		i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1785,10 @@ static void __devexit cyberpro_pci_remov
 			printk(KERN_WARNING "%s: danger Will Robinson, "
 				"danger danger!  Oopsen imminent!\n",
 				cfb->fb.fix.id);
+#ifdef CONFIG_FB_CYBER2000_I2C
+		if (cfb->ddc_registered)
+			i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-07-31 22:54:13.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_I2C
+	bool "DDC/I2C for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3 v2] cyber2000fb: add I2C support
  2010-07-31 22:13     ` Ondrej Zary
@ 2010-08-01  8:44       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 10+ messages in thread
From: Russell King - ARM Linux @ 2010-08-01  8:44 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: linux-fbdev, Kernel development list

On Sun, Aug 01, 2010 at 12:13:37AM +0200, Ondrej Zary wrote:
> 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>
> ---
> This is v2 with added locking and ddc things properly named.
> 
> diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
> --- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
> +++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 00:02:59.000000000 +0200
> @@ -48,6 +48,10 @@
>  #include <linux/init.h>
>  #include <linux/io.h>
>  
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.h>
> +#include <linux/i2c-algo-bit.h>
> +
>  #include <asm/pgtable.h>
>  #include <asm/system.h>
>  
> @@ -88,6 +92,12 @@ struct cfb_info {
>  	u_char			ramdac_powerdown;
>  
>  	u32			pseudo_palette[16];
> +#ifdef CONFIG_FB_CYBER2000_I2C

CONFIG_FB_CYBER2000_DDC please.

> +	bool			ddc_registered;
> +	struct i2c_adapter	ddc_adapter;
> +	struct i2c_algo_bit_data	ddc_algo;
> +	struct mutex		reg_b0_lock;

Does the weight of a mutex really matter here, or would a spinlock be
lighter weight?
> +static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
> +{
> +	mutex_lock(&cfb->reg_b0_lock);
> +	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
> +}
> +
> +static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
> +{
> +	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
> +	mutex_unlock(&cfb->reg_b0_lock);
> +}
> +
> +
> +static void cyber2000fb_setscl(void *data, int val)

cyber2000fb_ddc_setscl

> +{
> +	struct cfb_info *cfb = data;
> +	unsigned char reg;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	reg = cyber2000_grphr(DDC_REG, cfb);
> +	if (!val)	/* bit is inverted */
> +		reg |= DDC_SCL_OUT;
> +	else
> +		reg &= ~DDC_SCL_OUT;
> +	cyber2000_grphw(DDC_REG, reg, cfb);
> +	cyber2000fb_disable_ddc(cfb);
> +}
> +
> +static void cyber2000fb_setsda(void *data, int val)

cyber2000fb_ddc_setsda

> +{
> +	struct cfb_info *cfb = data;
> +	unsigned char reg;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	reg = cyber2000_grphr(DDC_REG, cfb);
> +	if (!val)	/* bit is inverted */
> +		reg |= DDC_SDA_OUT;
> +	else
> +		reg &= ~DDC_SDA_OUT;
> +	cyber2000_grphw(DDC_REG, reg, cfb);
> +	cyber2000fb_disable_ddc(cfb);
> +}
> +
> +static int cyber2000fb_getscl(void *data)

cyber2000fb_ddc_getscl

> +{
> +	struct cfb_info *cfb = data;
> +	int retval;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
> +	cyber2000fb_disable_ddc(cfb);
> +
> +	return retval;
> +}
> +
> +static int cyber2000fb_getsda(void *data)

cyber2000fb_ddc_getsda

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3 v2] cyber2000fb: add I2C support
@ 2010-08-01  8:44       ` Russell King - ARM Linux
  0 siblings, 0 replies; 10+ messages in thread
From: Russell King - ARM Linux @ 2010-08-01  8:44 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: linux-fbdev, Kernel development list

On Sun, Aug 01, 2010 at 12:13:37AM +0200, Ondrej Zary wrote:
> 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>
> ---
> This is v2 with added locking and ddc things properly named.
> 
> diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
> --- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
> +++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 00:02:59.000000000 +0200
> @@ -48,6 +48,10 @@
>  #include <linux/init.h>
>  #include <linux/io.h>
>  
> +#include <linux/i2c.h>
> +#include <linux/i2c-id.h>
> +#include <linux/i2c-algo-bit.h>
> +
>  #include <asm/pgtable.h>
>  #include <asm/system.h>
>  
> @@ -88,6 +92,12 @@ struct cfb_info {
>  	u_char			ramdac_powerdown;
>  
>  	u32			pseudo_palette[16];
> +#ifdef CONFIG_FB_CYBER2000_I2C

CONFIG_FB_CYBER2000_DDC please.

> +	bool			ddc_registered;
> +	struct i2c_adapter	ddc_adapter;
> +	struct i2c_algo_bit_data	ddc_algo;
> +	struct mutex		reg_b0_lock;

Does the weight of a mutex really matter here, or would a spinlock be
lighter weight?
> +static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
> +{
> +	mutex_lock(&cfb->reg_b0_lock);
> +	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
> +}
> +
> +static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
> +{
> +	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
> +	mutex_unlock(&cfb->reg_b0_lock);
> +}
> +
> +
> +static void cyber2000fb_setscl(void *data, int val)

cyber2000fb_ddc_setscl

> +{
> +	struct cfb_info *cfb = data;
> +	unsigned char reg;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	reg = cyber2000_grphr(DDC_REG, cfb);
> +	if (!val)	/* bit is inverted */
> +		reg |= DDC_SCL_OUT;
> +	else
> +		reg &= ~DDC_SCL_OUT;
> +	cyber2000_grphw(DDC_REG, reg, cfb);
> +	cyber2000fb_disable_ddc(cfb);
> +}
> +
> +static void cyber2000fb_setsda(void *data, int val)

cyber2000fb_ddc_setsda

> +{
> +	struct cfb_info *cfb = data;
> +	unsigned char reg;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	reg = cyber2000_grphr(DDC_REG, cfb);
> +	if (!val)	/* bit is inverted */
> +		reg |= DDC_SDA_OUT;
> +	else
> +		reg &= ~DDC_SDA_OUT;
> +	cyber2000_grphw(DDC_REG, reg, cfb);
> +	cyber2000fb_disable_ddc(cfb);
> +}
> +
> +static int cyber2000fb_getscl(void *data)

cyber2000fb_ddc_getscl

> +{
> +	struct cfb_info *cfb = data;
> +	int retval;
> +
> +	cyber2000fb_enable_ddc(cfb);
> +	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
> +	cyber2000fb_disable_ddc(cfb);
> +
> +	return retval;
> +}
> +
> +static int cyber2000fb_getsda(void *data)

cyber2000fb_ddc_getsda

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3 v3] cyber2000fb: add I2C support
  2010-08-01  8:44       ` Russell King - ARM Linux
@ 2010-08-01 10:07         ` Ondrej Zary
  -1 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-08-01 10:07 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>
---
This is v3 with spinlock instead of mutex (I don't know what's better here -
but both mode switch and DDC are not performance critical so it probably does
not matter) and all new things properly named ddc.

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 11:53:32.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,12 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_DDC
+	bool			ddc_registered;
+	struct i2c_adapter	ddc_adapter;
+	struct i2c_algo_bit_data	ddc_algo;
+	spinlock_t		reg_b0_lock;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -498,6 +508,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_attrw(0x14, 0x00, cfb);
 
 	/* PLL registers */
+#ifdef CONFIG_FB_CYBER2000_DDC
+	spin_lock(&cfb->reg_b0_lock);
+#endif
 	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
 	cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
 	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
@@ -505,6 +518,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_grphw(0x90, 0x01, cfb);
 	cyber2000_grphw(0xb9, 0x80, cfb);
 	cyber2000_grphw(0xb9, 0x00, cfb);
+#ifdef CONFIG_FB_CYBER2000_DDC
+	spin_unlock(&cfb->reg_b0_lock);
+#endif
 
 	cfb->ramdac_ctrl = hw->ramdac;
 	cyber2000fb_write_ramdac_ctrl(cfb);
@@ -1145,6 +1161,105 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_DDC
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
+{
+	spin_lock(&cfb->reg_b0_lock);
+	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
+{
+	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
+	spin_unlock(&cfb->reg_b0_lock);
+}
+
+
+static void cyber2000fb_ddc_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static void cyber2000fb_ddc_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static int cyber2000fb_ddc_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_ddc_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+{
+	spin_lock_init(&cfb->reg_b0_lock);
+
+	strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+		sizeof(cfb->ddc_adapter.name));
+	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_algo.setsda		= cyber2000fb_ddc_setsda;
+	cfb->ddc_algo.setscl		= cyber2000fb_ddc_setscl;
+	cfb->ddc_algo.getsda		= cyber2000fb_ddc_getsda;
+	cfb->ddc_algo.getscl		= cyber2000fb_ddc_getscl;
+	cfb->ddc_algo.udelay		= 10;
+	cfb->ddc_algo.timeout		= 20;
+	cfb->ddc_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->ddc_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->ddc_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_DDC */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1488,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_DDC
+	if (cyber2000fb_setup_ddc_bus(cfb) == 0)
+		cfb->ddc_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1530,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_DDC
+	if (err && cfb->ddc_registered)
+		i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1785,10 @@ static void __devexit cyberpro_pci_remov
 			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
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-08-01 11:48:32.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_DDC
+	bool "DDC for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3 v3] cyber2000fb: add I2C support
@ 2010-08-01 10:07         ` Ondrej Zary
  0 siblings, 0 replies; 10+ messages in thread
From: Ondrej Zary @ 2010-08-01 10:07 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: linux-fbdev, Kernel development list

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>
---
This is v3 with spinlock instead of mutex (I don't know what's better here -
but both mode switch and DDC are not performance critical so it probably does
not matter) and all new things properly named ddc.

diff -urp linux-2.6.35-rc3-/drivers/video/cyber2000fb.c linux-2.6.35-rc3/drivers/video/cyber2000fb.c
--- linux-2.6.35-rc3-/drivers/video/cyber2000fb.c	2010-07-31 21:58:35.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/cyber2000fb.c	2010-08-01 11:53:32.000000000 +0200
@@ -48,6 +48,10 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
@@ -88,6 +92,12 @@ struct cfb_info {
 	u_char			ramdac_powerdown;
 
 	u32			pseudo_palette[16];
+#ifdef CONFIG_FB_CYBER2000_DDC
+	bool			ddc_registered;
+	struct i2c_adapter	ddc_adapter;
+	struct i2c_algo_bit_data	ddc_algo;
+	spinlock_t		reg_b0_lock;
+#endif
 };
 
 static char *default_font = "Acorn8x8";
@@ -498,6 +508,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_attrw(0x14, 0x00, cfb);
 
 	/* PLL registers */
+#ifdef CONFIG_FB_CYBER2000_DDC
+	spin_lock(&cfb->reg_b0_lock);
+#endif
 	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
 	cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
 	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
@@ -505,6 +518,9 @@ static void cyber2000fb_set_timing(struc
 	cyber2000_grphw(0x90, 0x01, cfb);
 	cyber2000_grphw(0xb9, 0x80, cfb);
 	cyber2000_grphw(0xb9, 0x00, cfb);
+#ifdef CONFIG_FB_CYBER2000_DDC
+	spin_unlock(&cfb->reg_b0_lock);
+#endif
 
 	cfb->ramdac_ctrl = hw->ramdac;
 	cyber2000fb_write_ramdac_ctrl(cfb);
@@ -1145,6 +1161,105 @@ void cyber2000fb_detach(int idx)
 }
 EXPORT_SYMBOL(cyber2000fb_detach);
 
+#ifdef CONFIG_FB_CYBER2000_DDC
+
+#define DDC_REG		0xb0
+#define DDC_SCL_OUT	(1 << 0)
+#define DDC_SDA_OUT	(1 << 4)
+#define DDC_SCL_IN	(1 << 2)
+#define DDC_SDA_IN	(1 << 6)
+
+static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
+{
+	spin_lock(&cfb->reg_b0_lock);
+	cyber2000fb_writew(0x1bf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
+{
+	cyber2000fb_writew(0x0bf, 0x3ce, cfb);
+	spin_unlock(&cfb->reg_b0_lock);
+}
+
+
+static void cyber2000fb_ddc_setscl(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SCL_OUT;
+	else
+		reg &= ~DDC_SCL_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static void cyber2000fb_ddc_setsda(void *data, int val)
+{
+	struct cfb_info *cfb = data;
+	unsigned char reg;
+
+	cyber2000fb_enable_ddc(cfb);
+	reg = cyber2000_grphr(DDC_REG, cfb);
+	if (!val)	/* bit is inverted */
+		reg |= DDC_SDA_OUT;
+	else
+		reg &= ~DDC_SDA_OUT;
+	cyber2000_grphw(DDC_REG, reg, cfb);
+	cyber2000fb_disable_ddc(cfb);
+}
+
+static int cyber2000fb_ddc_getscl(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int cyber2000fb_ddc_getsda(void *data)
+{
+	struct cfb_info *cfb = data;
+	int retval;
+
+	cyber2000fb_enable_ddc(cfb);
+	retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+	cyber2000fb_disable_ddc(cfb);
+
+	return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+{
+	spin_lock_init(&cfb->reg_b0_lock);
+
+	strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+		sizeof(cfb->ddc_adapter.name));
+	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_algo.setsda		= cyber2000fb_ddc_setsda;
+	cfb->ddc_algo.setscl		= cyber2000fb_ddc_setscl;
+	cfb->ddc_algo.getsda		= cyber2000fb_ddc_getsda;
+	cfb->ddc_algo.getscl		= cyber2000fb_ddc_getscl;
+	cfb->ddc_algo.udelay		= 10;
+	cfb->ddc_algo.timeout		= 20;
+	cfb->ddc_algo.data		= cfb;
+
+	i2c_set_adapdata(&cfb->ddc_adapter, cfb);
+
+	return i2c_bit_add_bus(&cfb->ddc_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_DDC */
+
 /*
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1373,6 +1488,11 @@ static int __devinit cyberpro_common_pro
 	cfb->fb.fix.mmio_len   = MMIO_SIZE;
 	cfb->fb.screen_base    = cfb->region;
 
+#ifdef CONFIG_FB_CYBER2000_DDC
+	if (cyber2000fb_setup_ddc_bus(cfb) = 0)
+		cfb->ddc_registered = true;
+#endif
+
 	err = -EINVAL;
 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, mode_option, NULL, 0,
 			  &cyber2000fb_default_mode, 8)) {
@@ -1410,6 +1530,10 @@ static int __devinit cyberpro_common_pro
 	err = register_framebuffer(&cfb->fb);
 
 failed:
+#ifdef CONFIG_FB_CYBER2000_DDC
+	if (err && cfb->ddc_registered)
+		i2c_del_adapter(&cfb->ddc_adapter);
+#endif
 	return err;
 }
 
@@ -1661,6 +1785,10 @@ static void __devexit cyberpro_pci_remov
 			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
 		iounmap(cfb->region);
 		cyberpro_free_fb_info(cfb);
 
diff -urp linux-2.6.35-rc3-/drivers/video/Kconfig linux-2.6.35-rc3/drivers/video/Kconfig
--- linux-2.6.35-rc3-/drivers/video/Kconfig	2010-07-31 22:00:23.000000000 +0200
+++ linux-2.6.35-rc3/drivers/video/Kconfig	2010-08-01 11:48:32.000000000 +0200
@@ -422,6 +422,15 @@ config FB_CYBER2000
 	  Say Y if you have a NetWinder or a graphics card containing this
 	  device, otherwise say N.
 
+config FB_CYBER2000_DDC
+	bool "DDC for CyberPro support"
+	depends on FB_CYBER2000
+	select FB_DDC
+	default y
+	help
+	  Say Y here if you want DDC support for your CyberPro graphics
+	  card. This is only I2C bus support, driver does not use EDID.
+
 config FB_APOLLO
 	bool
 	depends on (FB = y) && APOLLO


-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-08-01 10:07 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-31 20:55 [PATCH 3/3] cyber2000fb: add I2C support Ondrej Zary
2010-07-31 20:55 ` Ondrej Zary
2010-07-31 21:42 ` Russell King - ARM Linux
2010-07-31 21:42   ` Russell King - ARM Linux
2010-07-31 22:13   ` [PATCH 3/3 v2] " Ondrej Zary
2010-07-31 22:13     ` Ondrej Zary
2010-08-01  8:44     ` Russell King - ARM Linux
2010-08-01  8:44       ` Russell King - ARM Linux
2010-08-01 10:07       ` [PATCH 3/3 v3] " Ondrej Zary
2010-08-01 10:07         ` Ondrej Zary

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.