1 /* 2 * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2 3 * 4 * Copyright 2004 Antonino A. Daplas <adaplas @pol.net> 5 * 6 * Based partly on rivafb-i2c.c 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file COPYING in the main directory of this archive 10 * for more details. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/delay.h> 16 #include <linux/gfp.h> 17 #include <linux/pci.h> 18 #include <linux/fb.h> 19 20 #include <asm/io.h> 21 #include "savagefb.h" 22 23 #define SAVAGE_DDC 0x50 24 25 #define VGA_CR_IX 0x3d4 26 #define VGA_CR_DATA 0x3d5 27 28 #define CR_SERIAL1 0xa0 /* I2C serial communications interface */ 29 #define MM_SERIAL1 0xff20 30 #define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */ 31 32 /* based on vt8365 documentation */ 33 #define PROSAVAGE_I2C_ENAB 0x10 34 #define PROSAVAGE_I2C_SCL_OUT 0x01 35 #define PROSAVAGE_I2C_SDA_OUT 0x02 36 #define PROSAVAGE_I2C_SCL_IN 0x04 37 #define PROSAVAGE_I2C_SDA_IN 0x08 38 39 #define SAVAGE4_I2C_ENAB 0x00000020 40 #define SAVAGE4_I2C_SCL_OUT 0x00000001 41 #define SAVAGE4_I2C_SDA_OUT 0x00000002 42 #define SAVAGE4_I2C_SCL_IN 0x00000008 43 #define SAVAGE4_I2C_SDA_IN 0x00000010 44 45 static void savage4_gpio_setscl(void *data, int val) 46 { 47 struct savagefb_i2c_chan *chan = data; 48 unsigned int r; 49 50 r = readl(chan->ioaddr + chan->reg); 51 if(val) 52 r |= SAVAGE4_I2C_SCL_OUT; 53 else 54 r &= ~SAVAGE4_I2C_SCL_OUT; 55 writel(r, chan->ioaddr + chan->reg); 56 readl(chan->ioaddr + chan->reg); /* flush posted write */ 57 } 58 59 static void savage4_gpio_setsda(void *data, int val) 60 { 61 struct savagefb_i2c_chan *chan = data; 62 63 unsigned int r; 64 r = readl(chan->ioaddr + chan->reg); 65 if(val) 66 r |= SAVAGE4_I2C_SDA_OUT; 67 else 68 r &= ~SAVAGE4_I2C_SDA_OUT; 69 writel(r, chan->ioaddr + chan->reg); 70 readl(chan->ioaddr + chan->reg); /* flush posted write */ 71 } 72 73 static int savage4_gpio_getscl(void *data) 74 { 75 struct savagefb_i2c_chan *chan = data; 76 77 return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN)); 78 } 79 80 static int savage4_gpio_getsda(void *data) 81 { 82 struct savagefb_i2c_chan *chan = data; 83 84 return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN)); 85 } 86 87 static void prosavage_gpio_setscl(void* data, int val) 88 { 89 struct savagefb_i2c_chan *chan = data; 90 u32 r; 91 92 r = VGArCR(chan->reg, chan->par); 93 r |= PROSAVAGE_I2C_ENAB; 94 if (val) { 95 r |= PROSAVAGE_I2C_SCL_OUT; 96 } else { 97 r &= ~PROSAVAGE_I2C_SCL_OUT; 98 } 99 100 VGAwCR(chan->reg, r, chan->par); 101 } 102 103 static void prosavage_gpio_setsda(void* data, int val) 104 { 105 struct savagefb_i2c_chan *chan = data; 106 unsigned int r; 107 108 r = VGArCR(chan->reg, chan->par); 109 r |= PROSAVAGE_I2C_ENAB; 110 if (val) { 111 r |= PROSAVAGE_I2C_SDA_OUT; 112 } else { 113 r &= ~PROSAVAGE_I2C_SDA_OUT; 114 } 115 116 VGAwCR(chan->reg, r, chan->par); 117 } 118 119 static int prosavage_gpio_getscl(void* data) 120 { 121 struct savagefb_i2c_chan *chan = data; 122 123 return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SCL_IN) ? 1 : 0; 124 } 125 126 static int prosavage_gpio_getsda(void* data) 127 { 128 struct savagefb_i2c_chan *chan = data; 129 130 return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SDA_IN) ? 1 : 0; 131 } 132 133 static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, 134 const char *name) 135 { 136 int rc = 0; 137 138 if (chan->par) { 139 strcpy(chan->adapter.name, name); 140 chan->adapter.owner = THIS_MODULE; 141 chan->adapter.algo_data = &chan->algo; 142 chan->adapter.dev.parent = &chan->par->pcidev->dev; 143 chan->algo.udelay = 10; 144 chan->algo.timeout = 20; 145 chan->algo.data = chan; 146 147 i2c_set_adapdata(&chan->adapter, chan); 148 149 /* Raise SCL and SDA */ 150 chan->algo.setsda(chan, 1); 151 chan->algo.setscl(chan, 1); 152 udelay(20); 153 154 rc = i2c_bit_add_bus(&chan->adapter); 155 156 if (rc == 0) 157 dev_dbg(&chan->par->pcidev->dev, 158 "I2C bus %s registered.\n", name); 159 else 160 dev_warn(&chan->par->pcidev->dev, 161 "Failed to register I2C bus %s.\n", name); 162 } 163 164 return rc; 165 } 166 167 void savagefb_create_i2c_busses(struct fb_info *info) 168 { 169 struct savagefb_par *par = info->par; 170 par->chan.par = par; 171 172 switch (par->chip) { 173 case S3_PROSAVAGE: 174 case S3_PROSAVAGEDDR: 175 case S3_TWISTER: 176 par->chan.reg = CR_SERIAL2; 177 par->chan.ioaddr = par->mmio.vbase; 178 par->chan.algo.setsda = prosavage_gpio_setsda; 179 par->chan.algo.setscl = prosavage_gpio_setscl; 180 par->chan.algo.getsda = prosavage_gpio_getsda; 181 par->chan.algo.getscl = prosavage_gpio_getscl; 182 break; 183 case S3_SAVAGE4: 184 par->chan.reg = CR_SERIAL1; 185 if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40)) 186 par->chan.reg = CR_SERIAL2; 187 par->chan.ioaddr = par->mmio.vbase; 188 par->chan.algo.setsda = prosavage_gpio_setsda; 189 par->chan.algo.setscl = prosavage_gpio_setscl; 190 par->chan.algo.getsda = prosavage_gpio_getsda; 191 par->chan.algo.getscl = prosavage_gpio_getscl; 192 break; 193 case S3_SAVAGE2000: 194 par->chan.reg = MM_SERIAL1; 195 par->chan.ioaddr = par->mmio.vbase; 196 par->chan.algo.setsda = savage4_gpio_setsda; 197 par->chan.algo.setscl = savage4_gpio_setscl; 198 par->chan.algo.getsda = savage4_gpio_getsda; 199 par->chan.algo.getscl = savage4_gpio_getscl; 200 break; 201 default: 202 par->chan.par = NULL; 203 } 204 205 savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2"); 206 } 207 208 void savagefb_delete_i2c_busses(struct fb_info *info) 209 { 210 struct savagefb_par *par = info->par; 211 212 if (par->chan.par) 213 i2c_del_adapter(&par->chan.adapter); 214 215 par->chan.par = NULL; 216 } 217 218 int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) 219 { 220 struct savagefb_par *par = info->par; 221 u8 *edid; 222 223 if (par->chan.par) 224 edid = fb_ddc_read(&par->chan.adapter); 225 else 226 edid = NULL; 227 228 if (!edid) { 229 /* try to get from firmware */ 230 const u8 *e = fb_firmware_edid(info->device); 231 232 if (e) 233 edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL); 234 } 235 236 *out_edid = edid; 237 238 return (edid) ? 0 : 1; 239 } 240 241 MODULE_LICENSE("GPL"); 242