Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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