Rev 420 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
420 | giacomo | 1 | /* |
2 | i2c-via.c - Part of lm_sensors, Linux kernel modules |
||
3 | for hardware monitoring |
||
4 | |||
5 | i2c Support for Via Technologies 82C586B South Bridge |
||
6 | |||
7 | Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi> |
||
8 | |||
9 | This program is free software; you can redistribute it and/or modify |
||
10 | it under the terms of the GNU General Public License as published by |
||
11 | the Free Software Foundation; either version 2 of the License, or |
||
12 | (at your option) any later version. |
||
13 | |||
14 | This program is distributed in the hope that it will be useful, |
||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | GNU General Public License for more details. |
||
18 | |||
19 | You should have received a copy of the GNU General Public License |
||
20 | along with this program; if not, write to the Free Software |
||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
22 | */ |
||
23 | |||
24 | #define DEBUG |
||
25 | |||
26 | #include <linux/kernel.h> |
||
27 | #include <linux/module.h> |
||
28 | #include <linux/pci.h> |
||
29 | #include <linux/ioport.h> |
||
30 | #include <linux/init.h> |
||
31 | #include <linux/i2c.h> |
||
32 | #include <linux/i2c-algo-bit.h> |
||
33 | #include <asm/io.h> |
||
34 | |||
35 | /* Power management registers */ |
||
36 | #define PM_CFG_REVID 0x08 /* silicon revision code */ |
||
37 | #define PM_CFG_IOBASE0 0x20 |
||
38 | #define PM_CFG_IOBASE1 0x48 |
||
39 | |||
40 | #define I2C_DIR (pm_io_base+0x40) |
||
41 | #define I2C_OUT (pm_io_base+0x42) |
||
42 | #define I2C_IN (pm_io_base+0x44) |
||
43 | #define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */ |
||
44 | #define I2C_SDA 0x04 |
||
45 | |||
46 | /* io-region reservation */ |
||
47 | #define IOSPACE 0x06 |
||
48 | #define IOTEXT "via-i2c" |
||
49 | |||
50 | static u16 pm_io_base = 0; |
||
51 | |||
52 | /* |
||
53 | It does not appear from the datasheet that the GPIO pins are |
||
54 | open drain. So a we set a low value by setting the direction to |
||
55 | output and a high value by setting the direction to input and |
||
56 | relying on the required I2C pullup. The data value is initialized |
||
57 | to 0 in via_init() and never changed. |
||
58 | */ |
||
59 | static void bit_via_setscl(void *data, int state) |
||
60 | { |
||
61 | outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL, I2C_DIR); |
||
62 | } |
||
63 | |||
64 | static void bit_via_setsda(void *data, int state) |
||
65 | { |
||
66 | outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA, I2C_DIR); |
||
67 | } |
||
68 | |||
69 | static int bit_via_getscl(void *data) |
||
70 | { |
||
71 | return (0 != (inb(I2C_IN) & I2C_SCL)); |
||
72 | } |
||
73 | |||
74 | static int bit_via_getsda(void *data) |
||
75 | { |
||
76 | return (0 != (inb(I2C_IN) & I2C_SDA)); |
||
77 | } |
||
78 | |||
79 | |||
80 | static struct i2c_algo_bit_data bit_data = { |
||
81 | .setsda = bit_via_setsda, |
||
82 | .setscl = bit_via_setscl, |
||
83 | .getsda = bit_via_getsda, |
||
84 | .getscl = bit_via_getscl, |
||
85 | .udelay = 5, |
||
86 | .mdelay = 5, |
||
87 | .timeout = HZ |
||
88 | }; |
||
89 | |||
90 | static struct i2c_adapter vt586b_adapter = { |
||
91 | .owner = THIS_MODULE, |
||
92 | .name = "VIA i2c", |
||
93 | .algo_data = &bit_data, |
||
94 | }; |
||
95 | |||
96 | |||
97 | static struct pci_device_id vt586b_ids[] __devinitdata = { |
||
98 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, |
||
99 | { 0, } |
||
100 | }; |
||
101 | |||
102 | static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id) |
||
103 | { |
||
104 | u16 base; |
||
105 | u8 rev; |
||
106 | int res; |
||
107 | |||
108 | if (pm_io_base) { |
||
109 | dev_err(&dev->dev, "i2c-via: Will only support one host\n"); |
||
110 | return -ENODEV; |
||
111 | } |
||
112 | |||
113 | pci_read_config_byte(dev, PM_CFG_REVID, &rev); |
||
114 | |||
115 | switch (rev) { |
||
116 | case 0x00: |
||
117 | base = PM_CFG_IOBASE0; |
||
118 | break; |
||
119 | case 0x01: |
||
120 | case 0x10: |
||
121 | base = PM_CFG_IOBASE1; |
||
122 | break; |
||
123 | |||
124 | default: |
||
125 | base = PM_CFG_IOBASE1; |
||
126 | /* later revision */ |
||
127 | } |
||
128 | |||
129 | pci_read_config_word(dev, base, &pm_io_base); |
||
130 | pm_io_base &= (0xff << 8); |
||
131 | |||
132 | if (!request_region(I2C_DIR, IOSPACE, IOTEXT)) { |
||
133 | dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE); |
||
134 | return -ENODEV; |
||
135 | } |
||
136 | |||
137 | outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); |
||
138 | outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); |
||
139 | |||
140 | /* set up the driverfs linkage to our parent device */ |
||
141 | vt586b_adapter.dev.parent = &dev->dev; |
||
142 | |||
143 | res = i2c_bit_add_bus(&vt586b_adapter); |
||
144 | if ( res < 0 ) { |
||
145 | release_region(I2C_DIR, IOSPACE); |
||
146 | pm_io_base = 0; |
||
147 | return res; |
||
148 | } |
||
149 | return 0; |
||
150 | } |
||
151 | |||
152 | static void __devexit vt586b_remove(struct pci_dev *dev) |
||
153 | { |
||
154 | i2c_bit_del_bus(&vt586b_adapter); |
||
155 | release_region(I2C_DIR, IOSPACE); |
||
156 | pm_io_base = 0; |
||
157 | } |
||
158 | |||
159 | |||
160 | static struct pci_driver vt586b_driver = { |
||
161 | .name = "vt586b smbus", |
||
162 | .id_table = vt586b_ids, |
||
163 | .probe = vt586b_probe, |
||
164 | .remove = __devexit_p(vt586b_remove), |
||
165 | }; |
||
166 | |||
167 | static int __init i2c_vt586b_init(void) |
||
168 | { |
||
169 | return pci_module_init(&vt586b_driver); |
||
170 | } |
||
171 | |||
172 | static void __exit i2c_vt586b_exit(void) |
||
173 | { |
||
174 | pci_unregister_driver(&vt586b_driver); |
||
175 | } |
||
176 | |||
177 | |||
178 | MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>"); |
||
179 | MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge"); |
||
180 | MODULE_LICENSE("GPL"); |
||
181 | |||
182 | module_init(i2c_vt586b_init); |
||
183 | module_exit(i2c_vt586b_exit); |