Skip to content

Commit 5bc1200

Browse files
alekduJean Delvare
authored andcommitted
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>
1 parent f7050bd commit 5bc1200

File tree

3 files changed

+347
-0
lines changed

3 files changed

+347
-0
lines changed

drivers/i2c/busses/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ config I2C_I801
101101
This driver can also be built as a module. If so, the module
102102
will be called i2c-i801.
103103

104+
config I2C_ISCH
105+
tristate "Intel SCH SMBus 1.0"
106+
depends on PCI
107+
help
108+
Say Y here if you want to use SMBus controller on the Intel SCH
109+
based systems.
110+
111+
This driver can also be built as a module. If so, the module
112+
will be called i2c-isch.
113+
104114
config I2C_PIIX4
105115
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
106116
depends on PCI

drivers/i2c/busses/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
1010
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
1111
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
1212
obj-$(CONFIG_I2C_I801) += i2c-i801.o
13+
obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
1314
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
1415
obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
1516
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o

drivers/i2c/busses/i2c-isch.c

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
64+
static unsigned short sch_smba;
65+
static struct pci_driver sch_driver;
66+
static 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+
*/
73+
static 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+
*/
153+
static 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+
240+
static 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+
247+
static const struct i2c_algorithm smbus_algorithm = {
248+
.smbus_xfer = sch_access,
249+
.functionality = sch_func,
250+
};
251+
252+
static struct i2c_adapter sch_adapter = {
253+
.owner = THIS_MODULE,
254+
.class = I2C_CLASS_HWMON,
255+
.algo = &smbus_algorithm,
256+
};
257+
258+
static struct pci_device_id sch_ids[] = {
259+
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
260+
{ 0, }
261+
};
262+
263+
MODULE_DEVICE_TABLE(pci, sch_ids);
264+
265+
static 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+
305+
static 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+
314+
static 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+
321+
static int __init i2c_sch_init(void)
322+
{
323+
return pci_register_driver(&sch_driver);
324+
}
325+
326+
static void __exit i2c_sch_exit(void)
327+
{
328+
pci_unregister_driver(&sch_driver);
329+
}
330+
331+
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
332+
MODULE_DESCRIPTION("Intel SCH SMBus driver");
333+
MODULE_LICENSE("GPL");
334+
335+
module_init(i2c_sch_init);
336+
module_exit(i2c_sch_exit);

0 commit comments

Comments
 (0)