Back to home page

OSCL-LXR

 
 

    


0001  /*-*- linux-c -*-
0002  *  linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support
0003  *
0004  *      Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
0005  *      All Rights Reserved
0006  *
0007  *  This file is subject to the terms and conditions of the GNU General Public
0008  *  License. See the file COPYING in the main directory of this archive for
0009  *  more details.
0010  */
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/delay.h>
0014 #include <linux/gfp.h>
0015 #include <linux/pci.h>
0016 #include <linux/fb.h>
0017 #include "i810.h"
0018 #include "i810_regs.h"
0019 #include "i810_main.h"
0020 #include "../edid.h"
0021 
0022 /* bit locations in the registers */
0023 #define SCL_DIR_MASK        0x0001
0024 #define SCL_DIR         0x0002
0025 #define SCL_VAL_MASK        0x0004
0026 #define SCL_VAL_OUT     0x0008
0027 #define SCL_VAL_IN      0x0010
0028 #define SDA_DIR_MASK        0x0100
0029 #define SDA_DIR         0x0200
0030 #define SDA_VAL_MASK        0x0400
0031 #define SDA_VAL_OUT     0x0800
0032 #define SDA_VAL_IN      0x1000
0033 
0034 #define DEBUG  /* define this for verbose EDID parsing output */
0035 
0036 #ifdef DEBUG
0037 #define DPRINTK(fmt, args...) printk(fmt,## args)
0038 #else
0039 #define DPRINTK(fmt, args...)
0040 #endif
0041 
0042 static void i810i2c_setscl(void *data, int state)
0043 {
0044         struct i810fb_i2c_chan    *chan = data;
0045         struct i810fb_par         *par = chan->par;
0046     u8                        __iomem *mmio = par->mmio_start_virtual;
0047 
0048     if (state)
0049         i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK | SCL_VAL_MASK);
0050     else
0051         i810_writel(mmio, chan->ddc_base, SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
0052     i810_readl(mmio, chan->ddc_base);   /* flush posted write */
0053 }
0054 
0055 static void i810i2c_setsda(void *data, int state)
0056 {
0057         struct i810fb_i2c_chan    *chan = data;
0058         struct i810fb_par         *par = chan->par;
0059     u8                        __iomem *mmio = par->mmio_start_virtual;
0060 
0061     if (state)
0062         i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK | SDA_VAL_MASK);
0063     else
0064         i810_writel(mmio, chan->ddc_base, SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
0065     i810_readl(mmio, chan->ddc_base);   /* flush posted write */
0066 }
0067 
0068 static int i810i2c_getscl(void *data)
0069 {
0070         struct i810fb_i2c_chan    *chan = data;
0071         struct i810fb_par         *par = chan->par;
0072     u8                        __iomem *mmio = par->mmio_start_virtual;
0073 
0074     i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
0075     i810_writel(mmio, chan->ddc_base, 0);
0076     return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
0077 }
0078 
0079 static int i810i2c_getsda(void *data)
0080 {
0081         struct i810fb_i2c_chan    *chan = data;
0082         struct i810fb_par         *par = chan->par;
0083     u8                        __iomem *mmio = par->mmio_start_virtual;
0084 
0085     i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
0086     i810_writel(mmio, chan->ddc_base, 0);
0087     return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
0088 }
0089 
0090 static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
0091 {
0092         int rc;
0093 
0094         strcpy(chan->adapter.name, name);
0095         chan->adapter.owner             = THIS_MODULE;
0096         chan->adapter.algo_data         = &chan->algo;
0097         chan->adapter.dev.parent        = &chan->par->dev->dev;
0098     chan->algo.setsda               = i810i2c_setsda;
0099     chan->algo.setscl               = i810i2c_setscl;
0100     chan->algo.getsda               = i810i2c_getsda;
0101     chan->algo.getscl               = i810i2c_getscl;
0102     chan->algo.udelay               = 10;
0103         chan->algo.timeout              = (HZ/2);
0104         chan->algo.data                 = chan;
0105 
0106         i2c_set_adapdata(&chan->adapter, chan);
0107 
0108         /* Raise SCL and SDA */
0109         chan->algo.setsda(chan, 1);
0110         chan->algo.setscl(chan, 1);
0111         udelay(20);
0112 
0113         rc = i2c_bit_add_bus(&chan->adapter);
0114 
0115         if (rc == 0)
0116                 dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
0117         else {
0118                 dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
0119              "%s.\n", name);
0120         chan->par = NULL;
0121     }
0122 
0123         return rc;
0124 }
0125 
0126 void i810_create_i2c_busses(struct i810fb_par *par)
0127 {
0128         par->chan[0].par        = par;
0129     par->chan[1].par        = par;
0130     par->chan[2].par        = par;
0131 
0132     par->chan[0].ddc_base = GPIOA;
0133     i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
0134     par->chan[1].ddc_base = GPIOB;
0135     i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
0136     par->chan[2].ddc_base = GPIOC;
0137     i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
0138 }
0139 
0140 void i810_delete_i2c_busses(struct i810fb_par *par)
0141 {
0142         if (par->chan[0].par)
0143         i2c_del_adapter(&par->chan[0].adapter);
0144         par->chan[0].par = NULL;
0145 
0146     if (par->chan[1].par)
0147         i2c_del_adapter(&par->chan[1].adapter);
0148     par->chan[1].par = NULL;
0149 
0150     if (par->chan[2].par)
0151         i2c_del_adapter(&par->chan[2].adapter);
0152     par->chan[2].par = NULL;
0153 }
0154 
0155 int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
0156 {
0157     struct i810fb_par *par = info->par;
0158         u8 *edid = NULL;
0159 
0160     DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
0161     if (conn < par->ddc_num) {
0162         edid = fb_ddc_read(&par->chan[conn].adapter);
0163     } else {
0164         const u8 *e = fb_firmware_edid(info->device);
0165 
0166         if (e != NULL) {
0167             DPRINTK("i810-i2c: Getting EDID from BIOS\n");
0168             edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
0169         }
0170     }
0171 
0172     *out_edid = edid;
0173 
0174         return (edid) ? 0 : 1;
0175 }