aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tdfxfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tdfxfb.c')
-rw-r--r--drivers/video/tdfxfb.c200
1 files changed, 199 insertions, 1 deletions
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index ee64771fbe3d..bc6f916c53be 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -10,6 +10,12 @@
10 * Created : Thu Sep 23 18:17:43 1999, hmallat 10 * Created : Thu Sep 23 18:17:43 1999, hmallat
11 * Last modified: Tue Nov 2 21:19:47 1999, hmallat 11 * Last modified: Tue Nov 2 21:19:47 1999, hmallat
12 * 12 *
13 * I2C part copied from the i2c-voodoo3.c driver by:
14 * Frodo Looijaard <frodol@dds.nl>,
15 * Philip Edelbrock <phil@netroedge.com>,
16 * Ralph Metzler <rjkm@thp.uni-koeln.de>, and
17 * Mark D. Studebaker <mdsxyz123@yahoo.com>
18 *
13 * Lots of the information here comes from the Daryll Strauss' Banshee 19 * Lots of the information here comes from the Daryll Strauss' Banshee
14 * patches to the XF86 server, and the rest comes from the 3dfx 20 * patches to the XF86 server, and the rest comes from the 3dfx
15 * Banshee specification. I'm very much indebted to Daryll for his 21 * Banshee specification. I'm very much indebted to Daryll for his
@@ -1167,6 +1173,190 @@ static struct fb_ops tdfxfb_ops = {
1167#endif 1173#endif
1168}; 1174};
1169 1175
1176#ifdef CONFIG_FB_3DFX_I2C
1177/* The voo GPIO registers don't have individual masks for each bit
1178 so we always have to read before writing. */
1179
1180static void tdfxfb_i2c_setscl(void *data, int val)
1181{
1182 struct tdfxfb_i2c_chan *chan = data;
1183 struct tdfx_par *par = chan->par;
1184 unsigned int r;
1185
1186 r = tdfx_inl(par, VIDSERPARPORT);
1187 if (val)
1188 r |= I2C_SCL_OUT;
1189 else
1190 r &= ~I2C_SCL_OUT;
1191 tdfx_outl(par, VIDSERPARPORT, r);
1192 tdfx_inl(par, VIDSERPARPORT); /* flush posted write */
1193}
1194
1195static void tdfxfb_i2c_setsda(void *data, int val)
1196{
1197 struct tdfxfb_i2c_chan *chan = data;
1198 struct tdfx_par *par = chan->par;
1199 unsigned int r;
1200
1201 r = tdfx_inl(par, VIDSERPARPORT);
1202 if (val)
1203 r |= I2C_SDA_OUT;
1204 else
1205 r &= ~I2C_SDA_OUT;
1206 tdfx_outl(par, VIDSERPARPORT, r);
1207 tdfx_inl(par, VIDSERPARPORT); /* flush posted write */
1208}
1209
1210/* The GPIO pins are open drain, so the pins always remain outputs.
1211 We rely on the i2c-algo-bit routines to set the pins high before
1212 reading the input from other chips. */
1213
1214static int tdfxfb_i2c_getscl(void *data)
1215{
1216 struct tdfxfb_i2c_chan *chan = data;
1217 struct tdfx_par *par = chan->par;
1218
1219 return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SCL_IN));
1220}
1221
1222static int tdfxfb_i2c_getsda(void *data)
1223{
1224 struct tdfxfb_i2c_chan *chan = data;
1225 struct tdfx_par *par = chan->par;
1226
1227 return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SDA_IN));
1228}
1229
1230static void tdfxfb_ddc_setscl(void *data, int val)
1231{
1232 struct tdfxfb_i2c_chan *chan = data;
1233 struct tdfx_par *par = chan->par;
1234 unsigned int r;
1235
1236 r = tdfx_inl(par, VIDSERPARPORT);
1237 if (val)
1238 r |= DDC_SCL_OUT;
1239 else
1240 r &= ~DDC_SCL_OUT;
1241 tdfx_outl(par, VIDSERPARPORT, r);
1242 tdfx_inl(par, VIDSERPARPORT); /* flush posted write */
1243}
1244
1245static void tdfxfb_ddc_setsda(void *data, int val)
1246{
1247 struct tdfxfb_i2c_chan *chan = data;
1248 struct tdfx_par *par = chan->par;
1249 unsigned int r;
1250
1251 r = tdfx_inl(par, VIDSERPARPORT);
1252 if (val)
1253 r |= DDC_SDA_OUT;
1254 else
1255 r &= ~DDC_SDA_OUT;
1256 tdfx_outl(par, VIDSERPARPORT, r);
1257 tdfx_inl(par, VIDSERPARPORT); /* flush posted write */
1258}
1259
1260static int tdfxfb_ddc_getscl(void *data)
1261{
1262 struct tdfxfb_i2c_chan *chan = data;
1263 struct tdfx_par *par = chan->par;
1264
1265 return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SCL_IN));
1266}
1267
1268static int tdfxfb_ddc_getsda(void *data)
1269{
1270 struct tdfxfb_i2c_chan *chan = data;
1271 struct tdfx_par *par = chan->par;
1272
1273 return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN));
1274}
1275
1276static int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan,
1277 const char *name, struct device *dev)
1278{
1279 int rc;
1280
1281 strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
1282 chan->adapter.owner = THIS_MODULE;
1283 chan->adapter.class = I2C_CLASS_DDC;
1284 chan->adapter.algo_data = &chan->algo;
1285 chan->adapter.dev.parent = dev;
1286 chan->algo.setsda = tdfxfb_ddc_setsda;
1287 chan->algo.setscl = tdfxfb_ddc_setscl;
1288 chan->algo.getsda = tdfxfb_ddc_getsda;
1289 chan->algo.getscl = tdfxfb_ddc_getscl;
1290 chan->algo.udelay = 10;
1291 chan->algo.timeout = msecs_to_jiffies(500);
1292 chan->algo.data = chan;
1293
1294 i2c_set_adapdata(&chan->adapter, chan);
1295
1296 rc = i2c_bit_add_bus(&chan->adapter);
1297 if (rc == 0)
1298 DPRINTK("I2C bus %s registered.\n", name);
1299 else
1300 chan->par = NULL;
1301
1302 return rc;
1303}
1304
1305static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
1306 const char *name, struct device *dev)
1307{
1308 int rc;
1309
1310 strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
1311 chan->adapter.owner = THIS_MODULE;
1312 chan->adapter.class = I2C_CLASS_TV_ANALOG;
1313 chan->adapter.algo_data = &chan->algo;
1314 chan->adapter.dev.parent = dev;
1315 chan->algo.setsda = tdfxfb_i2c_setsda;
1316 chan->algo.setscl = tdfxfb_i2c_setscl;
1317 chan->algo.getsda = tdfxfb_i2c_getsda;
1318 chan->algo.getscl = tdfxfb_i2c_getscl;
1319 chan->algo.udelay = 10;
1320 chan->algo.timeout = msecs_to_jiffies(500);
1321 chan->algo.data = chan;
1322
1323 i2c_set_adapdata(&chan->adapter, chan);
1324
1325 rc = i2c_bit_add_bus(&chan->adapter);
1326 if (rc == 0)
1327 DPRINTK("I2C bus %s registered.\n", name);
1328 else
1329 chan->par = NULL;
1330
1331 return rc;
1332}
1333
1334static void __devinit tdfxfb_create_i2c_busses(struct fb_info *info)
1335{
1336 struct tdfx_par *par = info->par;
1337
1338 tdfx_outl(par, VIDINFORMAT, 0x8160);
1339 tdfx_outl(par, VIDSERPARPORT, 0xcffc0020);
1340
1341 par->chan[0].par = par;
1342 par->chan[1].par = par;
1343
1344 tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->dev);
1345 tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->dev);
1346}
1347
1348static void tdfxfb_delete_i2c_busses(struct tdfx_par *par)
1349{
1350 if (par->chan[0].par)
1351 i2c_del_adapter(&par->chan[0].adapter);
1352 par->chan[0].par = NULL;
1353
1354 if (par->chan[1].par)
1355 i2c_del_adapter(&par->chan[1].adapter);
1356 par->chan[1].par = NULL;
1357}
1358#endif /* CONFIG_FB_3DFX_I2C */
1359
1170/** 1360/**
1171 * tdfxfb_probe - Device Initializiation 1361 * tdfxfb_probe - Device Initializiation
1172 * 1362 *
@@ -1284,7 +1474,9 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
1284 if (hwcursor) 1474 if (hwcursor)
1285 info->fix.smem_len = (info->fix.smem_len - 1024) & 1475 info->fix.smem_len = (info->fix.smem_len - 1024) &
1286 (PAGE_MASK << 1); 1476 (PAGE_MASK << 1);
1287 1477#ifdef CONFIG_FB_3DFX_I2C
1478 tdfxfb_create_i2c_busses(info);
1479#endif
1288 if (!mode_option) 1480 if (!mode_option)
1289 mode_option = "640x480@60"; 1481 mode_option = "640x480@60";
1290 1482
@@ -1315,6 +1507,9 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
1315 return 0; 1507 return 0;
1316 1508
1317out_err_iobase: 1509out_err_iobase:
1510#ifdef CONFIG_FB_3DFX_I2C
1511 tdfxfb_delete_i2c_busses(default_par);
1512#endif
1318 if (default_par->mtrr_handle >= 0) 1513 if (default_par->mtrr_handle >= 0)
1319 mtrr_del(default_par->mtrr_handle, info->fix.smem_start, 1514 mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
1320 info->fix.smem_len); 1515 info->fix.smem_len);
@@ -1379,6 +1574,9 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev)
1379 struct tdfx_par *par = info->par; 1574 struct tdfx_par *par = info->par;
1380 1575
1381 unregister_framebuffer(info); 1576 unregister_framebuffer(info);
1577#ifdef CONFIG_FB_3DFX_I2C
1578 tdfxfb_delete_i2c_busses(par);
1579#endif
1382 if (par->mtrr_handle >= 0) 1580 if (par->mtrr_handle >= 0)
1383 mtrr_del(par->mtrr_handle, info->fix.smem_start, 1581 mtrr_del(par->mtrr_handle, info->fix.smem_start,
1384 info->fix.smem_len); 1582 info->fix.smem_len);