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 ...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. --
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 << ...Does the weight of a mutex really matter here, or would a spinlock be cyber2000fb_ddc_getsda --
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)
}
...| Greg KH | Og dreams of kernels |
| Jens Axboe | [PATCH 31/33] Fusion: sg chaining support |
| Arnd Bergmann | Re: finding your own dead "CONFIG_" variables |
