vserver 1.9.5.x5
[linux-2.6.git] / drivers / i2c / busses / i2c-prosavage.c
1 /*
2  *    kernel/busses/i2c-prosavage.c
3  *
4  *    i2c bus driver for S3/VIA 8365/8375 graphics processor.
5  *    Copyright (c) 2003 Henk Vergonet <henk@god.dyndns.org>
6  *    Based on code written by:
7  *      Frodo Looijaard <frodol@dds.nl>,
8  *      Philip Edelbrock <phil@netroedge.com>,
9  *      Ralph Metzler <rjkm@thp.uni-koeln.de>, and
10  *      Mark D. Studebaker <mdsxyz123@yahoo.com>
11  *      Simon Vogl
12  *      and others
13  *
14  *    Please read the lm_sensors documentation for details on use.
15  *
16  *    This program is free software; you can redistribute it and/or modify
17  *    it under the terms of the GNU General Public License as published by
18  *    the Free Software Foundation; either version 2 of the License, or
19  *    (at your option) any later version.
20  *
21  *    This program is distributed in the hope that it will be useful,
22  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *    GNU General Public License for more details.
25  *
26  *    You should have received a copy of the GNU General Public License
27  *    along with this program; if not, write to the Free Software
28  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  *
30  */
31 /*  18-05-2003 HVE - created
32  *  14-06-2003 HVE - adapted for lm_sensors2
33  *  17-06-2003 HVE - linux 2.5.xx compatible
34  *  18-06-2003 HVE - codingstyle
35  *  21-06-2003 HVE - compatibility lm_sensors2 and linux 2.5.xx
36  *                   codingstyle, mmio enabled
37  *
38  *  This driver interfaces to the I2C bus of the VIA north bridge embedded
39  *  ProSavage4/8 devices. Usefull for gaining access to the TV Encoder chips.
40  *
41  *  Graphics cores:
42  *   S3/VIA KM266/VT8375 aka ProSavage8
43  *   S3/VIA KM133/VT8365 aka Savage4
44  *
45  *  Two serial busses are implemented:
46  *   SERIAL1 - I2C serial communications interface
47  *   SERIAL2 - DDC2 monitor communications interface
48  *
49  *  Tested on a FX41 mainboard, see http://www.shuttle.com
50  * 
51  *
52  *  TODO:
53  *  - integration with prosavage framebuffer device
54  *    (Additional documentation needed :(
55  */
56
57 #include <linux/config.h>
58 #include <linux/module.h>
59 #include <linux/init.h>
60 #include <linux/pci.h>
61 #include <linux/i2c.h>
62 #include <linux/i2c-algo-bit.h>
63 #include <asm/io.h>
64
65 /*
66  * driver configuration
67  */
68 #define MAX_BUSSES      2
69
70 struct s_i2c_bus {
71         void __iomem *mmvga;
72         int     i2c_reg;
73         int     adap_ok;
74         struct i2c_adapter              adap;
75         struct i2c_algo_bit_data        algo;
76 };
77
78 struct s_i2c_chip {
79         void __iomem *mmio;
80         struct s_i2c_bus        i2c_bus[MAX_BUSSES];
81 };
82
83
84 /*
85  * i2c configuration
86  */
87 #ifndef I2C_HW_B_S3VIA
88 #define I2C_HW_B_S3VIA  0x18    /* S3VIA ProSavage adapter              */
89 #endif
90
91 /* delays */
92 #define CYCLE_DELAY     10
93 #define TIMEOUT         (HZ / 2)
94
95
96 /* 
97  * S3/VIA 8365/8375 registers
98  */
99 #define VGA_CR_IX       0x3d4
100 #define VGA_CR_DATA     0x3d5
101
102 #define CR_SERIAL1      0xa0    /* I2C serial communications interface */
103 #define MM_SERIAL1      0xff20
104 #define CR_SERIAL2      0xb1    /* DDC2 monitor communications interface */
105
106 /* based on vt8365 documentation */
107 #define I2C_ENAB        0x10
108 #define I2C_SCL_OUT     0x01
109 #define I2C_SDA_OUT     0x02
110 #define I2C_SCL_IN      0x04
111 #define I2C_SDA_IN      0x08
112
113 #define SET_CR_IX(p, val)       writeb((val), (p)->mmvga + VGA_CR_IX)
114 #define SET_CR_DATA(p, val)     writeb((val), (p)->mmvga + VGA_CR_DATA)
115 #define GET_CR_DATA(p)          readb((p)->mmvga + VGA_CR_DATA)
116
117
118 /*
119  * Serial bus line handling
120  *
121  * serial communications register as parameter in private data
122  *
123  * TODO: locks with other code sections accessing video registers?
124  */
125 static void bit_s3via_setscl(void *bus, int val)
126 {
127         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
128         unsigned int r;
129
130         SET_CR_IX(p, p->i2c_reg);
131         r = GET_CR_DATA(p);
132         r |= I2C_ENAB;
133         if (val) {
134                 r |= I2C_SCL_OUT;
135         } else {
136                 r &= ~I2C_SCL_OUT;
137         }
138         SET_CR_DATA(p, r);
139 }
140
141 static void bit_s3via_setsda(void *bus, int val)
142 {
143         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
144         unsigned int r;
145         
146         SET_CR_IX(p, p->i2c_reg);
147         r = GET_CR_DATA(p);
148         r |= I2C_ENAB;
149         if (val) {
150                 r |= I2C_SDA_OUT;
151         } else {
152                 r &= ~I2C_SDA_OUT;
153         }
154         SET_CR_DATA(p, r);
155 }
156
157 static int bit_s3via_getscl(void *bus)
158 {
159         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
160
161         SET_CR_IX(p, p->i2c_reg);
162         return (0 != (GET_CR_DATA(p) & I2C_SCL_IN));
163 }
164
165 static int bit_s3via_getsda(void *bus)
166 {
167         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
168
169         SET_CR_IX(p, p->i2c_reg);
170         return (0 != (GET_CR_DATA(p) & I2C_SDA_IN));
171 }
172
173
174 /*
175  * adapter initialisation
176  */
177 static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg)
178 {
179         int ret;
180         p->adap.owner     = THIS_MODULE;
181         p->adap.id        = I2C_HW_B_S3VIA;
182         p->adap.algo_data = &p->algo;
183         p->adap.dev.parent = &dev->dev;
184         p->algo.setsda    = bit_s3via_setsda;
185         p->algo.setscl    = bit_s3via_setscl;
186         p->algo.getsda    = bit_s3via_getsda;
187         p->algo.getscl    = bit_s3via_getscl;
188         p->algo.udelay    = CYCLE_DELAY;
189         p->algo.mdelay    = CYCLE_DELAY;
190         p->algo.timeout   = TIMEOUT;
191         p->algo.data      = p;
192         p->mmvga          = mmvga;
193         p->i2c_reg        = i2c_reg;
194     
195         ret = i2c_bit_add_bus(&p->adap);
196         if (ret) {
197                 return ret;
198         }
199
200         p->adap_ok = 1;
201         return 0;
202 }
203
204
205 /*
206  * Cleanup stuff
207  */
208 static void prosavage_remove(struct pci_dev *dev)
209 {
210         struct s_i2c_chip *chip;
211         int i, ret;
212
213         chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
214
215         if (!chip) {
216                 return;
217         }
218         for (i = MAX_BUSSES - 1; i >= 0; i--) {
219                 if (chip->i2c_bus[i].adap_ok == 0)
220                         continue;
221
222                 ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
223                 if (ret) {
224                         dev_err(&dev->dev, "%s not removed\n",
225                                 chip->i2c_bus[i].adap.name);
226                 }
227         }
228         if (chip->mmio) {
229                 iounmap(chip->mmio);
230         }
231         kfree(chip);
232 }
233
234
235 /*
236  * Detect chip and initialize it
237  */
238 static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_device_id *id)
239 {
240         int ret;
241         unsigned long base, len;
242         struct s_i2c_chip *chip;
243         struct s_i2c_bus  *bus;
244
245         pci_set_drvdata(dev, kmalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); 
246         chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
247         if (chip == NULL) {
248                 return -ENOMEM;
249         }
250
251         memset(chip, 0, sizeof(struct s_i2c_chip));
252
253         base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK;
254         len  = dev->resource[0].end - base + 1;
255         chip->mmio = ioremap_nocache(base, len);
256
257         if (chip->mmio == NULL) {
258                 dev_err(&dev->dev, "ioremap failed\n");
259                 prosavage_remove(dev);
260                 return -ENODEV;
261         }
262
263
264         /*
265          * Chip initialisation
266          */
267         /* Unlock Extended IO Space ??? */
268
269
270         /*
271          * i2c bus registration
272          */
273         bus = &chip->i2c_bus[0];
274         snprintf(bus->adap.name, sizeof(bus->adap.name),
275                 "ProSavage I2C bus at %02x:%02x.%x",
276                 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
277         ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL1);
278         if (ret) {
279                 goto err_adap;
280         }
281         /*
282          * ddc bus registration
283          */
284         bus = &chip->i2c_bus[1];
285         snprintf(bus->adap.name, sizeof(bus->adap.name),
286                 "ProSavage DDC bus at %02x:%02x.%x",
287                 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
288         ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL2);
289         if (ret) {
290                 goto err_adap;
291         }
292         return 0;
293 err_adap:
294         dev_err(&dev->dev, "%s failed\n", bus->adap.name);
295         prosavage_remove(dev);
296         return ret;
297 }
298
299
300 /*
301  * Data for PCI driver interface
302  */
303 static struct pci_device_id prosavage_pci_tbl[] = {
304         { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SAVAGE4) },
305         { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_PROSAVAGE8) },
306         { 0, },
307 };
308
309 MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
310
311 static struct pci_driver prosavage_driver = {
312         .name           =       "prosavage_smbus",
313         .id_table       =       prosavage_pci_tbl,
314         .probe          =       prosavage_probe,
315         .remove         =       prosavage_remove,
316 };
317
318 static int __init i2c_prosavage_init(void)
319 {
320         return pci_register_driver(&prosavage_driver);
321 }
322
323 static void __exit i2c_prosavage_exit(void)
324 {
325         pci_unregister_driver(&prosavage_driver);
326 }
327
328 MODULE_DEVICE_TABLE(pci, prosavage_pci_tbl);
329 MODULE_AUTHOR("Henk Vergonet");
330 MODULE_DESCRIPTION("ProSavage VIA 8365/8375 smbus driver");
331 MODULE_LICENSE("GPL");
332
333 module_init (i2c_prosavage_init);
334 module_exit (i2c_prosavage_exit);