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