linux/drivers/video/i810/i810-i2c.c
<<
>>
Prefs
   1 /*-*- linux-c -*-
   2 *  linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support
   3 *
   4 *      Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
   5 *      All Rights Reserved
   6 *
   7 *  This file is subject to the terms and conditions of the GNU General Public
   8 *  License. See the file COPYING in the main directory of this archive for
   9 *  more details.
  10 */
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/delay.h>
  14#include <linux/pci.h>
  15#include <linux/fb.h>
  16#include "i810.h"
  17#include "i810_regs.h"
  18#include "i810_main.h"
  19#include "../edid.h"
  20
  21/* bit locations in the registers */
  22#define SCL_DIR_MASK            0x0001
  23#define SCL_DIR                 0x0002
  24#define SCL_VAL_MASK            0x0004
  25#define SCL_VAL_OUT             0x0008
  26#define SCL_VAL_IN              0x0010
  27#define SDA_DIR_MASK            0x0100
  28#define SDA_DIR                 0x0200
  29#define SDA_VAL_MASK            0x0400
  30#define SDA_VAL_OUT             0x0800
  31#define SDA_VAL_IN              0x1000
  32
  33#define DEBUG  /* define this for verbose EDID parsing output */
  34
  35#ifdef DEBUG
  36#define DPRINTK(fmt, args...) printk(fmt,## args)
  37#else
  38#define DPRINTK(fmt, args...)
  39#endif
  40
  41static void i810i2c_setscl(void *data, int state)
  42{
  43        struct i810fb_i2c_chan    *chan = data;
  44        struct i810fb_par         *par = chan->par;
  45        u8                        __iomem *mmio = par->mmio_start_virtual;
  46
  47        i810_writel(mmio, chan->ddc_base, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
  48                    SCL_DIR_MASK | SCL_VAL_MASK);
  49        i810_readl(mmio, chan->ddc_base);       /* flush posted write */
  50}
  51
  52static void i810i2c_setsda(void *data, int state)
  53{
  54        struct i810fb_i2c_chan    *chan = data;
  55        struct i810fb_par         *par = chan->par;
  56        u8                        __iomem *mmio = par->mmio_start_virtual;
  57
  58        i810_writel(mmio, chan->ddc_base, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
  59                    SDA_DIR_MASK | SDA_VAL_MASK);
  60        i810_readl(mmio, chan->ddc_base);       /* flush posted write */
  61}
  62
  63static int i810i2c_getscl(void *data)
  64{
  65        struct i810fb_i2c_chan    *chan = data;
  66        struct i810fb_par         *par = chan->par;
  67        u8                        __iomem *mmio = par->mmio_start_virtual;
  68
  69        i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
  70        i810_writel(mmio, chan->ddc_base, 0);
  71        return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
  72}
  73
  74static int i810i2c_getsda(void *data)
  75{
  76        struct i810fb_i2c_chan    *chan = data;
  77        struct i810fb_par         *par = chan->par;
  78        u8                        __iomem *mmio = par->mmio_start_virtual;
  79
  80        i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
  81        i810_writel(mmio, chan->ddc_base, 0);
  82        return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
  83}
  84
  85static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
  86{
  87        int rc;
  88
  89        strcpy(chan->adapter.name, name);
  90        chan->adapter.owner             = THIS_MODULE;
  91        chan->adapter.algo_data         = &chan->algo;
  92        chan->adapter.dev.parent        = &chan->par->dev->dev;
  93        chan->algo.setsda               = i810i2c_setsda;
  94        chan->algo.setscl               = i810i2c_setscl;
  95        chan->algo.getsda               = i810i2c_getsda;
  96        chan->algo.getscl               = i810i2c_getscl;
  97        chan->algo.udelay               = 10;
  98        chan->algo.timeout              = (HZ/2);
  99        chan->algo.data                 = chan;
 100
 101        i2c_set_adapdata(&chan->adapter, chan);
 102
 103        /* Raise SCL and SDA */
 104        chan->algo.setsda(chan, 1);
 105        chan->algo.setscl(chan, 1);
 106        udelay(20);
 107
 108        rc = i2c_bit_add_bus(&chan->adapter);
 109
 110        if (rc == 0)
 111                dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
 112        else {
 113                dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
 114                         "%s.\n", name);
 115                chan->par = NULL;
 116        }
 117
 118        return rc;
 119}
 120
 121void i810_create_i2c_busses(struct i810fb_par *par)
 122{
 123        par->chan[0].par        = par;
 124        par->chan[1].par        = par;
 125        par->chan[2].par        = par;
 126
 127        par->chan[0].ddc_base = GPIOA;
 128        i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
 129        par->chan[1].ddc_base = GPIOB;
 130        i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
 131        par->chan[2].ddc_base = GPIOC;
 132        i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
 133}
 134
 135void i810_delete_i2c_busses(struct i810fb_par *par)
 136{
 137        if (par->chan[0].par)
 138                i2c_del_adapter(&par->chan[0].adapter);
 139        par->chan[0].par = NULL;
 140
 141        if (par->chan[1].par)
 142                i2c_del_adapter(&par->chan[1].adapter);
 143        par->chan[1].par = NULL;
 144
 145        if (par->chan[2].par)
 146                i2c_del_adapter(&par->chan[2].adapter);
 147        par->chan[2].par = NULL;
 148}
 149
 150int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
 151{
 152        struct i810fb_par *par = info->par;
 153        u8 *edid = NULL;
 154
 155        DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
 156        if (conn < par->ddc_num) {
 157                edid = fb_ddc_read(&par->chan[conn].adapter);
 158        } else {
 159                const u8 *e = fb_firmware_edid(info->device);
 160
 161                if (e != NULL) {
 162                        DPRINTK("i810-i2c: Getting EDID from BIOS\n");
 163                        edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
 164                }
 165        }
 166
 167        *out_edid = edid;
 168
 169        return (edid) ? 0 : 1;
 170}
 171