aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-isch.c
diff options
context:
space:
mode:
authorAlek Du <alek.du@intel.com>2008-07-14 16:38:27 -0400
committerJean Delvare <khali@mahadeva.delvare>2008-07-14 16:38:27 -0400
commit5bc1200852c3dfc312481f57622f48b289ac802e (patch)
tree262c2e628d5a4e110e8a2cfff6934fe2469f75f4 /drivers/i2c/busses/i2c-isch.c
parentf7050bd716047a4dfec7d061e28df7ffd6815ebd (diff)
i2c: Add Intel SCH SMBus support
New i2c bus driver for the Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L). Signed-off-by: Alek Du <alek.du@intel.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-isch.c')
-rw-r--r--drivers/i2c/busses/i2c-isch.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
new file mode 100644
index 000000000000..c9cd46b22692
--- /dev/null
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -0,0 +1,336 @@
1/*
2 i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
3 - Based on i2c-piix4.c
4 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
5 Philip Edelbrock <phil@netroedge.com>
6 - Intel SCH support
7 Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com>
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 version 2 as
11 published by the Free Software Foundation.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/*
24 Supports:
25 Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
26 Note: we assume there can only be one device, with one SMBus interface.
27*/
28
29#include <linux/module.h>
30#include <linux/pci.h>
31#include <linux/kernel.h>
32#include <linux/delay.h>
33#include <linux/stddef.h>
34#include <linux/ioport.h>
35#include <linux/i2c.h>
36#include <linux/init.h>
37#include <linux/io.h>
38
39/* SCH SMBus address offsets */
40#define SMBHSTCNT (0 + sch_smba)
41#define SMBHSTSTS (1 + sch_smba)
42#define SMBHSTADD (4 + sch_smba) /* TSA */
43#define SMBHSTCMD (5 + sch_smba)
44#define SMBHSTDAT0 (6 + sch_smba)
45#define SMBHSTDAT1 (7 + sch_smba)
46#define SMBBLKDAT (0x20 + sch_smba)
47
48/* count for request_region */
49#define SMBIOSIZE 64
50
51/* PCI Address Constants */
52#define SMBBA_SCH 0x40
53
54/* Other settings */
55#define MAX_TIMEOUT 500
56
57/* I2C constants */
58#define SCH_QUICK 0x00
59#define SCH_BYTE 0x01
60#define SCH_BYTE_DATA 0x02
61#define SCH_WORD_DATA 0x03
62#define SCH_BLOCK_DATA 0x05
63
64static unsigned short sch_smba;
65static struct pci_driver sch_driver;
66static struct i2c_adapter sch_adapter;
67
68/*
69 * Start the i2c transaction -- the i2c_access will prepare the transaction
70 * and this function will execute it.
71 * return 0 for success and others for failure.
72 */
73static int sch_transaction(void)
74{
75 int temp;
76 int result = 0;
77 int timeout = 0;
78
79 dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
80 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
81 inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
82 inb(SMBHSTDAT1));
83
84 /* Make sure the SMBus host is ready to start transmitting */
85 temp = inb(SMBHSTSTS) & 0x0f;
86 if (temp) {
87 /* Can not be busy since we checked it in sch_access */
88 if (temp & 0x01) {
89 dev_dbg(&sch_adapter.dev, "Completion (%02x). "
90 "Clear...\n", temp);
91 }
92 if (temp & 0x06) {
93 dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
94 "Resetting...\n", temp);
95 }
96 outb(temp, SMBHSTSTS);
97 temp = inb(SMBHSTSTS) & 0x0f;
98 if (temp) {
99 dev_err(&sch_adapter.dev,
100 "SMBus is not ready: (%02x)\n", temp);
101 return -EAGAIN;
102 }
103 }
104
105 /* start the transaction by setting bit 4 */
106 outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
107
108 do {
109 msleep(1);
110 temp = inb(SMBHSTSTS) & 0x0f;
111 } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
112
113 /* If the SMBus is still busy, we give up */
114 if (timeout >= MAX_TIMEOUT) {
115 dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
116 result = -ETIMEDOUT;
117 }
118 if (temp & 0x04) {
119 result = -EIO;
120 dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
121 "locked until next hard reset. (sorry!)\n");
122 /* Clock stops and slave is stuck in mid-transmission */
123 } else if (temp & 0x02) {
124 result = -EIO;
125 dev_err(&sch_adapter.dev, "Error: no response!\n");
126 } else if (temp & 0x01) {
127 dev_dbg(&sch_adapter.dev, "Post complete!\n");
128 outb(temp, SMBHSTSTS);
129 temp = inb(SMBHSTSTS) & 0x07;
130 if (temp & 0x06) {
131 /* Completion clear failed */
132 dev_dbg(&sch_adapter.dev, "Failed reset at end of "
133 "transaction (%02x), Bus error!\n", temp);
134 }
135 } else {
136 result = -ENXIO;
137 dev_dbg(&sch_adapter.dev, "No such address.\n");
138 }
139 dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
140 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
141 inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
142 inb(SMBHSTDAT1));
143 return result;
144}
145
146/*
147 * This is the main access entry for i2c-sch access
148 * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
149 * (0 for read and 1 for write), size is i2c transaction type and data is the
150 * union of transaction for data to be transfered or data read from bus.
151 * return 0 for success and others for failure.
152 */
153static s32 sch_access(struct i2c_adapter *adap, u16 addr,
154 unsigned short flags, char read_write,
155 u8 command, int size, union i2c_smbus_data *data)
156{
157 int i, len, temp, rc;
158
159 /* Make sure the SMBus host is not busy */
160 temp = inb(SMBHSTSTS) & 0x0f;
161 if (temp & 0x08) {
162 dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
163 return -EAGAIN;
164 }
165 dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
166 (read_write)?"READ":"WRITE");
167 switch (size) {
168 case I2C_SMBUS_QUICK:
169 outb((addr << 1) | read_write, SMBHSTADD);
170 size = SCH_QUICK;
171 break;
172 case I2C_SMBUS_BYTE:
173 outb((addr << 1) | read_write, SMBHSTADD);
174 if (read_write == I2C_SMBUS_WRITE)
175 outb(command, SMBHSTCMD);
176 size = SCH_BYTE;
177 break;
178 case I2C_SMBUS_BYTE_DATA:
179 outb((addr << 1) | read_write, SMBHSTADD);
180 outb(command, SMBHSTCMD);
181 if (read_write == I2C_SMBUS_WRITE)
182 outb(data->byte, SMBHSTDAT0);
183 size = SCH_BYTE_DATA;
184 break;
185 case I2C_SMBUS_WORD_DATA:
186 outb((addr << 1) | read_write, SMBHSTADD);
187 outb(command, SMBHSTCMD);
188 if (read_write == I2C_SMBUS_WRITE) {
189 outb(data->word & 0xff, SMBHSTDAT0);
190 outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
191 }
192 size = SCH_WORD_DATA;
193 break;
194 case I2C_SMBUS_BLOCK_DATA:
195 outb((addr << 1) | read_write, SMBHSTADD);
196 outb(command, SMBHSTCMD);
197 if (read_write == I2C_SMBUS_WRITE) {
198 len = data->block[0];
199 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
200 return -EINVAL;
201 outb(len, SMBHSTDAT0);
202 for (i = 1; i <= len; i++)
203 outb(data->block[i], SMBBLKDAT+i-1);
204 }
205 size = SCH_BLOCK_DATA;
206 break;
207 default:
208 dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
209 return -EOPNOTSUPP;
210 }
211 dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
212 outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
213
214 rc = sch_transaction();
215 if (rc) /* Error in transaction */
216 return rc;
217
218 if ((read_write == I2C_SMBUS_WRITE) || (size == SCH_QUICK))
219 return 0;
220
221 switch (size) {
222 case SCH_BYTE:
223 case SCH_BYTE_DATA:
224 data->byte = inb(SMBHSTDAT0);
225 break;
226 case SCH_WORD_DATA:
227 data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
228 break;
229 case SCH_BLOCK_DATA:
230 data->block[0] = inb(SMBHSTDAT0);
231 if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
232 return -EPROTO;
233 for (i = 1; i <= data->block[0]; i++)
234 data->block[i] = inb(SMBBLKDAT+i-1);
235 break;
236 }
237 return 0;
238}
239
240static u32 sch_func(struct i2c_adapter *adapter)
241{
242 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
243 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
244 I2C_FUNC_SMBUS_BLOCK_DATA;
245}
246
247static const struct i2c_algorithm smbus_algorithm = {
248 .smbus_xfer = sch_access,
249 .functionality = sch_func,
250};
251
252static struct i2c_adapter sch_adapter = {
253 .owner = THIS_MODULE,
254 .class = I2C_CLASS_HWMON,
255 .algo = &smbus_algorithm,
256};
257
258static struct pci_device_id sch_ids[] = {
259 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
260 { 0, }
261};
262
263MODULE_DEVICE_TABLE(pci, sch_ids);
264
265static int __devinit sch_probe(struct pci_dev *dev,
266 const struct pci_device_id *id)
267{
268 int retval;
269 unsigned int smba;
270
271 pci_read_config_dword(dev, SMBBA_SCH, &smba);
272 if (!(smba & (1 << 31))) {
273 dev_err(&dev->dev, "SMBus I/O space disabled!\n");
274 return -ENODEV;
275 }
276
277 sch_smba = (unsigned short)smba;
278 if (sch_smba == 0) {
279 dev_err(&dev->dev, "SMBus base address uninitialized!\n");
280 return -ENODEV;
281 }
282 if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
283 dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
284 sch_smba);
285 return -EBUSY;
286 }
287 dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
288
289 /* set up the sysfs linkage to our parent device */
290 sch_adapter.dev.parent = &dev->dev;
291
292 snprintf(sch_adapter.name, sizeof(sch_adapter.name),
293 "SMBus SCH adapter at %04x", sch_smba);
294
295 retval = i2c_add_adapter(&sch_adapter);
296 if (retval) {
297 dev_err(&dev->dev, "Couldn't register adapter!\n");
298 release_region(sch_smba, SMBIOSIZE);
299 sch_smba = 0;
300 }
301
302 return retval;
303}
304
305static void __devexit sch_remove(struct pci_dev *dev)
306{
307 if (sch_smba) {
308 i2c_del_adapter(&sch_adapter);
309 release_region(sch_smba, SMBIOSIZE);
310 sch_smba = 0;
311 }
312}
313
314static struct pci_driver sch_driver = {
315 .name = "isch_smbus",
316 .id_table = sch_ids,
317 .probe = sch_probe,
318 .remove = __devexit_p(sch_remove),
319};
320
321static int __init i2c_sch_init(void)
322{
323 return pci_register_driver(&sch_driver);
324}
325
326static void __exit i2c_sch_exit(void)
327{
328 pci_unregister_driver(&sch_driver);
329}
330
331MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
332MODULE_DESCRIPTION("Intel SCH SMBus driver");
333MODULE_LICENSE("GPL");
334
335module_init(i2c_sch_init);
336module_exit(i2c_sch_exit);