242 lines · c
1/*2 * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC23 *4 * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>5 *6 * Based partly on rivafb-i2c.c7 *8 * This file is subject to the terms and conditions of the GNU General Public9 * License. See the file COPYING in the main directory of this archive10 * 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 0x5024 25#define VGA_CR_IX 0x3d426#define VGA_CR_DATA 0x3d527 28#define CR_SERIAL1 0xa0 /* I2C serial communications interface */29#define MM_SERIAL1 0xff2030#define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */31 32/* based on vt8365 documentation */33#define PROSAVAGE_I2C_ENAB 0x1034#define PROSAVAGE_I2C_SCL_OUT 0x0135#define PROSAVAGE_I2C_SDA_OUT 0x0236#define PROSAVAGE_I2C_SCL_IN 0x0437#define PROSAVAGE_I2C_SDA_IN 0x0838 39#define SAVAGE4_I2C_ENAB 0x0000002040#define SAVAGE4_I2C_SCL_OUT 0x0000000141#define SAVAGE4_I2C_SDA_OUT 0x0000000242#define SAVAGE4_I2C_SCL_IN 0x0000000843#define SAVAGE4_I2C_SDA_IN 0x0000001044 45static 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 else54 r &= ~SAVAGE4_I2C_SCL_OUT;55 writel(r, chan->ioaddr + chan->reg);56 readl(chan->ioaddr + chan->reg); /* flush posted write */57}58 59static 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 else68 r &= ~SAVAGE4_I2C_SDA_OUT;69 writel(r, chan->ioaddr + chan->reg);70 readl(chan->ioaddr + chan->reg); /* flush posted write */71}72 73static 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 80static 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 87static 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 103static 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 119static 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 126static 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 133static 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 else160 dev_warn(&chan->par->pcidev->dev,161 "Failed to register I2C bus %s.\n", name);162 }163 164 return rc;165}166 167void 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 208void 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 218int 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 else226 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 241MODULE_LICENSE("GPL");242