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