Subversion Repositories shark

Rev

Rev 420 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
420 giacomo 1
/*
2
    voodoo3.c - Part of lm_sensors, Linux kernel modules for hardware
3
              monitoring
4
    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
5
    Philip Edelbrock <phil@netroedge.com>,
6
    Ralph Metzler <rjkm@thp.uni-koeln.de>, and
7
    Mark D. Studebaker <mdsxyz123@yahoo.com>
8
 
9
    Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
10
    Simon Vogl
11
 
12
    This program is free software; you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation; either version 2 of the License, or
15
    (at your option) any later version.
16
 
17
    This program is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
 
22
    You should have received a copy of the GNU General Public License
23
    along with this program; if not, write to the Free Software
24
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
*/
26
 
27
/* This interfaces to the I2C bus of the Voodoo3 to gain access to
28
    the BT869 and possibly other I2C devices. */
29
 
30
#include <linux/kernel.h>
31
#include <linux/module.h>
32
#include <linux/init.h>
33
#include <linux/pci.h>
34
#include <linux/i2c.h>
35
#include <linux/i2c-algo-bit.h>
36
#include <asm/io.h>
37
 
38
/* the only registers we use */
39
#define REG             0x78
40
#define REG2            0x70
41
 
42
/* bit locations in the register */
43
#define DDC_ENAB        0x00040000
44
#define DDC_SCL_OUT     0x00080000
45
#define DDC_SDA_OUT     0x00100000
46
#define DDC_SCL_IN      0x00200000
47
#define DDC_SDA_IN      0x00400000
48
#define I2C_ENAB        0x00800000
49
#define I2C_SCL_OUT     0x01000000
50
#define I2C_SDA_OUT     0x02000000
51
#define I2C_SCL_IN      0x04000000
52
#define I2C_SDA_IN      0x08000000
53
 
54
/* initialization states */
55
#define INIT2           0x2
56
#define INIT3           0x4
57
 
58
/* delays */
59
#define CYCLE_DELAY     10
60
#define TIMEOUT         (HZ / 2)
61
 
62
 
63
static void *ioaddr;
64
 
65
/* The voo GPIO registers don't have individual masks for each bit
66
   so we always have to read before writing. */
67
 
68
static void bit_vooi2c_setscl(void *data, int val)
69
{
70
        unsigned int r;
71
        r = readl(ioaddr + REG);
72
        if (val)
73
                r |= I2C_SCL_OUT;
74
        else
75
                r &= ~I2C_SCL_OUT;
76
        writel(r, ioaddr + REG);
77
        readl(ioaddr + REG);    /* flush posted write */
78
}
79
 
80
static void bit_vooi2c_setsda(void *data, int val)
81
{
82
        unsigned int r;
83
        r = readl(ioaddr + REG);
84
        if (val)
85
                r |= I2C_SDA_OUT;
86
        else
87
                r &= ~I2C_SDA_OUT;
88
        writel(r, ioaddr + REG);
89
        readl(ioaddr + REG);    /* flush posted write */
90
}
91
 
92
/* The GPIO pins are open drain, so the pins always remain outputs.
93
   We rely on the i2c-algo-bit routines to set the pins high before
94
   reading the input from other chips. */
95
 
96
static int bit_vooi2c_getscl(void *data)
97
{
98
        return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
99
}
100
 
101
static int bit_vooi2c_getsda(void *data)
102
{
103
        return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
104
}
105
 
106
static void bit_vooddc_setscl(void *data, int val)
107
{
108
        unsigned int r;
109
        r = readl(ioaddr + REG);
110
        if (val)
111
                r |= DDC_SCL_OUT;
112
        else
113
                r &= ~DDC_SCL_OUT;
114
        writel(r, ioaddr + REG);
115
        readl(ioaddr + REG);    /* flush posted write */
116
}
117
 
118
static void bit_vooddc_setsda(void *data, int val)
119
{
120
        unsigned int r;
121
        r = readl(ioaddr + REG);
122
        if (val)
123
                r |= DDC_SDA_OUT;
124
        else
125
                r &= ~DDC_SDA_OUT;
126
        writel(r, ioaddr + REG);
127
        readl(ioaddr + REG);    /* flush posted write */
128
}
129
 
130
static int bit_vooddc_getscl(void *data)
131
{
132
        return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
133
}
134
 
135
static int bit_vooddc_getsda(void *data)
136
{
137
        return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
138
}
139
 
140
static int config_v3(struct pci_dev *dev)
141
{
142
        unsigned int cadr;
143
 
144
        /* map Voodoo3 memory */
145
        cadr = dev->resource[0].start;
146
        cadr &= PCI_BASE_ADDRESS_MEM_MASK;
147
        ioaddr = ioremap_nocache(cadr, 0x1000);
148
        if (ioaddr) {
149
                writel(0x8160, ioaddr + REG2);
150
                writel(0xcffc0020, ioaddr + REG);
151
                dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
152
                return 0;
153
        }
154
        return -ENODEV;
155
}
156
 
157
static struct i2c_algo_bit_data voo_i2c_bit_data = {
158
        .setsda         = bit_vooi2c_setsda,
159
        .setscl         = bit_vooi2c_setscl,
160
        .getsda         = bit_vooi2c_getsda,
161
        .getscl         = bit_vooi2c_getscl,
162
        .udelay         = CYCLE_DELAY,
163
        .mdelay         = CYCLE_DELAY,
164
        .timeout        = TIMEOUT
165
};
166
 
167
static struct i2c_adapter voodoo3_i2c_adapter = {
168
        .owner          = THIS_MODULE,
169
        .name           = "I2C Voodoo3/Banshee adapter",
170
        .algo_data      = &voo_i2c_bit_data,
171
};
172
 
173
static struct i2c_algo_bit_data voo_ddc_bit_data = {
174
        .setsda         = bit_vooddc_setsda,
175
        .setscl         = bit_vooddc_setscl,
176
        .getsda         = bit_vooddc_getsda,
177
        .getscl         = bit_vooddc_getscl,
178
        .udelay         = CYCLE_DELAY,
179
        .mdelay         = CYCLE_DELAY,
180
        .timeout        = TIMEOUT
181
};
182
 
183
static struct i2c_adapter voodoo3_ddc_adapter = {
184
        .owner          = THIS_MODULE,
185
        .name           = "DDC Voodoo3/Banshee adapter",
186
        .algo_data      = &voo_ddc_bit_data,
187
};
188
 
189
static struct pci_device_id voodoo3_ids[] __devinitdata = {
190
        { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
191
        { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
192
        { 0, }
193
};
194
 
195
static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
196
{
197
        int retval;
198
 
199
        retval = config_v3(dev);
200
        if (retval)
201
                return retval;
202
 
203
        /* set up the sysfs linkage to our parent device */
204
        voodoo3_i2c_adapter.dev.parent = &dev->dev;
205
        voodoo3_ddc_adapter.dev.parent = &dev->dev;
206
 
207
        retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
208
        if (retval)
209
                return retval;
210
        retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
211
        if (retval)
212
                i2c_bit_del_bus(&voodoo3_i2c_adapter);
213
        return retval;
214
}
215
 
216
static void __devexit voodoo3_remove(struct pci_dev *dev)
217
{
218
        i2c_bit_del_bus(&voodoo3_i2c_adapter);
219
        i2c_bit_del_bus(&voodoo3_ddc_adapter);
220
        iounmap(ioaddr);
221
}
222
 
223
static struct pci_driver voodoo3_driver = {
224
        .name           = "voodoo3 smbus",
225
        .id_table       = voodoo3_ids,
226
        .probe          = voodoo3_probe,
227
        .remove         = __devexit_p(voodoo3_remove),
228
};
229
 
230
static int __init i2c_voodoo3_init(void)
231
{
232
        return pci_module_init(&voodoo3_driver);
233
}
234
 
235
static void __exit i2c_voodoo3_exit(void)
236
{
237
        pci_unregister_driver(&voodoo3_driver);
238
}
239
 
240
 
241
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
242
                "Philip Edelbrock <phil@netroedge.com>, "
243
                "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
244
                "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
245
MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
246
MODULE_LICENSE("GPL");
247
 
248
module_init(i2c_voodoo3_init);
249
module_exit(i2c_voodoo3_exit);