commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / drivers / i2c / 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/version.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
64 #include <asm/io.h>
65
66
67 /*
68  * driver configuration
69  */
70 #define DRIVER_ID       "i2c-prosavage"
71 #define DRIVER_VERSION  "20030621"
72
73 #define ADAPTER_NAME(x) (x).name
74
75 #define MAX_BUSSES      2
76
77 struct s_i2c_bus {
78         u8      *mmvga;
79         int     i2c_reg;
80         int     adap_ok;
81         struct i2c_adapter              adap;
82         struct i2c_algo_bit_data        algo;
83 };
84
85 struct s_i2c_chip {
86         u8      *mmio;
87         struct s_i2c_bus        i2c_bus[MAX_BUSSES];
88 };
89
90
91 /*
92  * i2c configuration
93  */
94 #ifndef I2C_HW_B_S3VIA
95 #define I2C_HW_B_S3VIA  0x18    /* S3VIA ProSavage adapter              */
96 #endif
97
98 /* delays */
99 #define CYCLE_DELAY     10
100 #define TIMEOUT         (HZ / 2)
101
102
103 /* 
104  * S3/VIA 8365/8375 registers
105  */
106 #ifndef PCI_VENDOR_ID_S3
107 #define PCI_VENDOR_ID_S3                0x5333
108 #endif
109 #ifndef PCI_DEVICE_ID_S3_SAVAGE4
110 #define PCI_DEVICE_ID_S3_SAVAGE4        0x8a25
111 #endif
112 #ifndef PCI_DEVICE_ID_S3_PROSAVAGE8
113 #define PCI_DEVICE_ID_S3_PROSAVAGE8     0x8d04
114 #endif
115
116 #define VGA_CR_IX       0x3d4
117 #define VGA_CR_DATA     0x3d5
118
119 #define CR_SERIAL1      0xa0    /* I2C serial communications interface */
120 #define MM_SERIAL1      0xff20
121 #define CR_SERIAL2      0xb1    /* DDC2 monitor communications interface */
122
123 /* based on vt8365 documentation */
124 #define I2C_ENAB        0x10
125 #define I2C_SCL_OUT     0x01
126 #define I2C_SDA_OUT     0x02
127 #define I2C_SCL_IN      0x04
128 #define I2C_SDA_IN      0x08
129
130 #define SET_CR_IX(p, val)       *((p)->mmvga + VGA_CR_IX) = (u8)(val)
131 #define SET_CR_DATA(p, val)     *((p)->mmvga + VGA_CR_DATA) = (u8)(val)
132 #define GET_CR_DATA(p)          *((p)->mmvga + VGA_CR_DATA)
133
134
135 /*
136  * Serial bus line handling
137  *
138  * serial communications register as parameter in private data
139  *
140  * TODO: locks with other code sections accessing video registers?
141  */
142 static void bit_s3via_setscl(void *bus, int val)
143 {
144         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
145         unsigned int r;
146
147         SET_CR_IX(p, p->i2c_reg);
148         r = GET_CR_DATA(p);
149         r |= I2C_ENAB;
150         if (val) {
151                 r |= I2C_SCL_OUT;
152         } else {
153                 r &= ~I2C_SCL_OUT;
154         }
155         SET_CR_DATA(p, r);
156 }
157
158 static void bit_s3via_setsda(void *bus, int val)
159 {
160         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
161         unsigned int r;
162         
163         SET_CR_IX(p, p->i2c_reg);
164         r = GET_CR_DATA(p);
165         r |= I2C_ENAB;
166         if (val) {
167                 r |= I2C_SDA_OUT;
168         } else {
169                 r &= ~I2C_SDA_OUT;
170         }
171         SET_CR_DATA(p, r);
172 }
173
174 static int bit_s3via_getscl(void *bus)
175 {
176         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
177
178         SET_CR_IX(p, p->i2c_reg);
179         return (0 != (GET_CR_DATA(p) & I2C_SCL_IN));
180 }
181
182 static int bit_s3via_getsda(void *bus)
183 {
184         struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
185
186         SET_CR_IX(p, p->i2c_reg);
187         return (0 != (GET_CR_DATA(p) & I2C_SDA_IN));
188 }
189
190
191 /*
192  * adapter initialisation
193  */
194 static int i2c_register_bus(struct s_i2c_bus *p, u8 *mmvga, u32 i2c_reg)
195 {
196         int ret;
197         p->adap.owner     = THIS_MODULE;
198         p->adap.id        = I2C_HW_B_S3VIA;
199         p->adap.algo_data = &p->algo;
200         p->algo.setsda    = bit_s3via_setsda;
201         p->algo.setscl    = bit_s3via_setscl;
202         p->algo.getsda    = bit_s3via_getsda;
203         p->algo.getscl    = bit_s3via_getscl;
204         p->algo.udelay    = CYCLE_DELAY;
205         p->algo.mdelay    = CYCLE_DELAY;
206         p->algo.timeout   = TIMEOUT;
207         p->algo.data      = p;
208         p->mmvga          = mmvga;
209         p->i2c_reg        = i2c_reg;
210     
211         ret = i2c_bit_add_bus(&p->adap);
212         if (ret) {
213                 return ret;
214         }
215
216         p->adap_ok = 1;
217         return 0;
218 }
219
220
221 /*
222  * Cleanup stuff
223  */
224 static void __devexit prosavage_remove(struct pci_dev *dev)
225 {
226         struct s_i2c_chip *chip;
227         int i, ret;
228
229         chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
230
231         if (!chip) {
232                 return;
233         }
234         for (i = MAX_BUSSES - 1; i >= 0; i--) {
235                 if (chip->i2c_bus[i].adap_ok == 0)
236                         continue;
237
238                 ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
239                 if (ret) {
240                         printk(DRIVER_ID ": %s not removed\n",
241                                 ADAPTER_NAME(chip->i2c_bus[i].adap));
242                 }
243         }
244         if (chip->mmio) {
245                 iounmap(chip->mmio);
246         }
247         kfree(chip);
248 }
249
250
251 /*
252  * Detect chip and initialize it
253  */
254 static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_device_id *id)
255 {
256         int ret;
257         unsigned long base, len;
258         struct s_i2c_chip *chip;
259         struct s_i2c_bus  *bus;
260
261         pci_set_drvdata(dev, kmalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); 
262         chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
263         if (chip == NULL) {
264                 return -ENOMEM;
265         }
266
267         memset(chip, 0, sizeof(struct s_i2c_chip));
268
269         base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK;
270         len  = dev->resource[0].end - base + 1;
271         chip->mmio = ioremap_nocache(base, len);
272
273         if (chip->mmio == NULL) {
274                 printk (DRIVER_ID ": ioremap failed\n");
275                 prosavage_remove(dev);
276                 return -ENODEV;
277         }
278
279
280         /*
281          * Chip initialisation
282          */
283         /* Unlock Extended IO Space ??? */
284
285
286         /*
287          * i2c bus registration
288          */
289         bus = &chip->i2c_bus[0];
290         snprintf(ADAPTER_NAME(bus->adap), sizeof(ADAPTER_NAME(bus->adap)),
291                 "ProSavage I2C bus at %02x:%02x.%x",
292                 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
293         ret = i2c_register_bus(bus, chip->mmio + 0x8000, CR_SERIAL1);
294         if (ret) {
295                 goto err_adap;
296         }
297         /*
298          * ddc bus registration
299          */
300         bus = &chip->i2c_bus[1];
301         snprintf(ADAPTER_NAME(bus->adap), sizeof(ADAPTER_NAME(bus->adap)),
302                 "ProSavage DDC bus at %02x:%02x.%x",
303                 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
304         ret = i2c_register_bus(bus, chip->mmio + 0x8000, CR_SERIAL2);
305         if (ret) {
306                 goto err_adap;
307         }
308         return 0;
309 err_adap:
310         printk (DRIVER_ID ": %s failed\n", ADAPTER_NAME(bus->adap));
311         prosavage_remove(dev);
312         return ret;
313 }
314
315
316 /*
317  * Data for PCI driver interface
318  */
319 static struct pci_device_id prosavage_pci_tbl[] = {
320    {
321         .vendor         =       PCI_VENDOR_ID_S3,
322         .device         =       PCI_DEVICE_ID_S3_SAVAGE4,
323         .subvendor      =       PCI_ANY_ID,
324         .subdevice      =       PCI_ANY_ID,
325    },{
326         .vendor         =       PCI_VENDOR_ID_S3,
327         .device         =       PCI_DEVICE_ID_S3_PROSAVAGE8,
328         .subvendor      =       PCI_ANY_ID,
329         .subdevice      =       PCI_ANY_ID,
330    },{ 0, }
331 };
332
333 static struct pci_driver prosavage_driver = {
334         .name           =       "prosavage-smbus",
335         .id_table       =       prosavage_pci_tbl,
336         .probe          =       prosavage_probe,
337         .remove         =       __devexit_p(prosavage_remove),
338 };
339
340 static int __init i2c_prosavage_init(void)
341 {
342         printk(DRIVER_ID " version %s (%s)\n", I2C_VERSION, DRIVER_VERSION);
343         return pci_module_init(&prosavage_driver);
344 }
345
346 static void __exit i2c_prosavage_exit(void)
347 {
348         pci_unregister_driver(&prosavage_driver);
349 }
350
351 MODULE_DEVICE_TABLE(pci, prosavage_pci_tbl);
352 MODULE_AUTHOR("Henk Vergonet");
353 MODULE_DESCRIPTION("ProSavage VIA 8365/8375 smbus driver");
354 MODULE_LICENSE("GPL");
355
356 module_init (i2c_prosavage_init);
357 module_exit (i2c_prosavage_exit);