[PATCH] i810fb: Cleanup I2C code
- The functions for reading the 1st and 2nd bus are essentially the same, except for the register. Consolidate them all. - According to Nicolas Boichat, there is an undocumented 3rd i2c bus for attaching daughter cards. Add support for this. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Родитель
8a0934f296
Коммит
5fab851ea1
|
@ -46,92 +46,45 @@ static void i810i2c_setscl(void *data, int state)
|
|||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
|
||||
i810_writel(mmio, chan->ddc_base, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
|
||||
SCL_DIR_MASK | SCL_VAL_MASK);
|
||||
i810_readl(mmio, GPIOB); /* flush posted write */
|
||||
i810_readl(mmio, chan->ddc_base); /* flush posted write */
|
||||
}
|
||||
|
||||
static void i810i2c_setsda(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_i2c_chan *chan = data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
|
||||
i810_writel(mmio, chan->ddc_base, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
|
||||
SDA_DIR_MASK | SDA_VAL_MASK);
|
||||
i810_readl(mmio, GPIOB); /* flush posted write */
|
||||
i810_readl(mmio, chan->ddc_base); /* flush posted write */
|
||||
}
|
||||
|
||||
static int i810i2c_getscl(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_i2c_chan *chan = data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, SCL_DIR_MASK);
|
||||
i810_writel(mmio, GPIOB, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOB) & SCL_VAL_IN));
|
||||
i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
|
||||
i810_writel(mmio, chan->ddc_base, 0);
|
||||
return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
|
||||
}
|
||||
|
||||
static int i810i2c_getsda(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_i2c_chan *chan = data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, SDA_DIR_MASK);
|
||||
i810_writel(mmio, GPIOB, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOB) & SDA_VAL_IN));
|
||||
i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
|
||||
i810_writel(mmio, chan->ddc_base, 0);
|
||||
return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
|
||||
}
|
||||
|
||||
static void i810ddc_setscl(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
|
||||
SCL_DIR_MASK | SCL_VAL_MASK);
|
||||
i810_readl(mmio, GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static void i810ddc_setsda(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
|
||||
SDA_DIR_MASK | SDA_VAL_MASK);
|
||||
i810_readl(mmio, GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static int i810ddc_getscl(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, SCL_DIR_MASK);
|
||||
i810_writel(mmio, GPIOA, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOA) & SCL_VAL_IN));
|
||||
}
|
||||
|
||||
static int i810ddc_getsda(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 __iomem *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, SDA_DIR_MASK);
|
||||
i810_writel(mmio, GPIOA, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOA) & SDA_VAL_IN));
|
||||
}
|
||||
|
||||
#define I2C_ALGO_DDC_I810 0x0e0000
|
||||
#define I2C_ALGO_I2C_I810 0x0f0000
|
||||
static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name,
|
||||
int conn)
|
||||
static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -139,22 +92,11 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name,
|
|||
chan->adapter.owner = THIS_MODULE;
|
||||
chan->adapter.algo_data = &chan->algo;
|
||||
chan->adapter.dev.parent = &chan->par->dev->dev;
|
||||
switch (conn) {
|
||||
case 1:
|
||||
chan->adapter.id = I2C_ALGO_DDC_I810;
|
||||
chan->algo.setsda = i810ddc_setsda;
|
||||
chan->algo.setscl = i810ddc_setscl;
|
||||
chan->algo.getsda = i810ddc_getsda;
|
||||
chan->algo.getscl = i810ddc_getscl;
|
||||
break;
|
||||
case 2:
|
||||
chan->adapter.id = I2C_ALGO_I2C_I810;
|
||||
chan->algo.setsda = i810i2c_setsda;
|
||||
chan->algo.setscl = i810i2c_setscl;
|
||||
chan->algo.getsda = i810i2c_getsda;
|
||||
chan->algo.getscl = i810i2c_getscl;
|
||||
break;
|
||||
}
|
||||
chan->adapter.id = I2C_HW_B_I810;
|
||||
chan->algo.setsda = i810i2c_setsda;
|
||||
chan->algo.setscl = i810i2c_setscl;
|
||||
chan->algo.getsda = i810i2c_getsda;
|
||||
chan->algo.getscl = i810i2c_getscl;
|
||||
chan->algo.udelay = 10;
|
||||
chan->algo.mdelay = 10;
|
||||
chan->algo.timeout = (HZ/2);
|
||||
|
@ -168,11 +110,15 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name,
|
|||
udelay(20);
|
||||
|
||||
rc = i2c_bit_add_bus(&chan->adapter);
|
||||
|
||||
if (rc == 0)
|
||||
dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
|
||||
else
|
||||
else {
|
||||
dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
|
||||
"%s.\n", name);
|
||||
chan->par = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -180,8 +126,14 @@ void i810_create_i2c_busses(struct i810fb_par *par)
|
|||
{
|
||||
par->chan[0].par = par;
|
||||
par->chan[1].par = par;
|
||||
i810_setup_i2c_bus(&par->chan[0], "I810-DDC", 1);
|
||||
i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 2);
|
||||
par->chan[2].par = par;
|
||||
|
||||
par->chan[0].ddc_base = GPIOA;
|
||||
i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
|
||||
par->chan[1].ddc_base = GPIOB;
|
||||
i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
|
||||
par->chan[2].ddc_base = GPIOC;
|
||||
i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
|
||||
}
|
||||
|
||||
void i810_delete_i2c_busses(struct i810fb_par *par)
|
||||
|
@ -189,9 +141,14 @@ void i810_delete_i2c_busses(struct i810fb_par *par)
|
|||
if (par->chan[0].par)
|
||||
i2c_bit_del_bus(&par->chan[0].adapter);
|
||||
par->chan[0].par = NULL;
|
||||
|
||||
if (par->chan[1].par)
|
||||
i2c_bit_del_bus(&par->chan[1].adapter);
|
||||
par->chan[1].par = NULL;
|
||||
|
||||
if (par->chan[2].par)
|
||||
i2c_bit_del_bus(&par->chan[2].adapter);
|
||||
par->chan[2].par = NULL;
|
||||
}
|
||||
|
||||
static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan)
|
||||
|
@ -221,6 +178,7 @@ static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan)
|
|||
DPRINTK("i810-i2c: I2C Transfer successful\n");
|
||||
return buf;
|
||||
}
|
||||
|
||||
DPRINTK("i810-i2c: Unable to read EDID block.\n");
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
|
@ -233,7 +191,7 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
|
|||
int i;
|
||||
|
||||
DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn);
|
||||
if (conn < 3) {
|
||||
if (conn < 4) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Do the real work */
|
||||
edid = i810_do_probe_i2c_edid(&par->chan[conn-1]);
|
||||
|
@ -241,11 +199,14 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
DPRINTK("i810-i2c: Getting EDID from BIOS\n");
|
||||
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (edid)
|
||||
memcpy(edid, fb_firmware_edid(info->device),
|
||||
EDID_LENGTH);
|
||||
const u8 *e = fb_firmware_edid(info->device);
|
||||
|
||||
if (e != NULL) {
|
||||
DPRINTK("i810-i2c: Getting EDID from BIOS\n");
|
||||
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (edid)
|
||||
memcpy(edid, e, EDID_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_edid)
|
||||
|
@ -253,5 +214,3 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
|
|||
|
||||
return (edid) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -249,6 +249,7 @@ struct i810fb_i2c_chan {
|
|||
struct i810fb_par *par;
|
||||
struct i2c_adapter adapter;
|
||||
struct i2c_algo_bit_data algo;
|
||||
unsigned long ddc_base;
|
||||
};
|
||||
|
||||
struct i810fb_par {
|
||||
|
@ -262,7 +263,7 @@ struct i810fb_par {
|
|||
struct heap_data iring;
|
||||
struct heap_data cursor_heap;
|
||||
struct vgastate state;
|
||||
struct i810fb_i2c_chan chan[2];
|
||||
struct i810fb_i2c_chan chan[3];
|
||||
atomic_t use_count;
|
||||
u32 pseudo_palette[17];
|
||||
unsigned long mmio_start_phys;
|
||||
|
|
|
@ -1854,7 +1854,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info)
|
|||
#ifdef CONFIG_FB_I810_I2C
|
||||
i810_create_i2c_busses(par);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = i810_probe_i2c_connector(info, &par->edid, i+1);
|
||||
if (!err)
|
||||
break;
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#define HVSYNC 0x05000
|
||||
#define GPIOA 0x05010
|
||||
#define GPIOB 0x05014
|
||||
#define GPIOC 0x0501C
|
||||
|
||||
/* Clock Control and Power Management Registers (06000h 06FFFh) */
|
||||
#define DCLK_0D 0x06000
|
||||
|
|
Загрузка…
Ссылка в новой задаче