You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: (26 commits) i2c-rpx: Remove i2c-mpc: work around missing-9th-clock-pulse bug i2c: New PMC MSP71xx TWI bus driver i2c-savage4: Delete many unused defines i2c/tsl2550: Speed up initialization i2c: New bus driver for the TAOS evaluation modules i2c-i801: Use the internal 32-byte buffer on ICH4+ i2c-i801: Various cleanups i2c: Add support for the TSL2550 i2c-pxa: Support new-style I2C drivers i2c-gpio: Make some internal functions static i2c-gpio: Add support for new-style clients i2c-iop3xx: Switch to static adapter numbering i2c-sis5595: Resolve resource conflict with sis5595 matroxfb: Clean-up i2c header inclusions i2c-nforce2: Add support for SMBus block transactions i2c-mpc: Use i2c_add_numbered_adapter i2c-mv64xxx: Use i2c_add_numbered_adapter i2c-piix4: Add support for the ATI SB700 i2c: New DS1682 chip driver ...
This commit is contained in:
@@ -643,6 +643,60 @@ X!Idrivers/video/console/fonts.c
|
||||
!Edrivers/spi/spi.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="i2c">
|
||||
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
|
||||
|
||||
<para>
|
||||
I<superscript>2</superscript>C (or without fancy typography, "I2C")
|
||||
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
|
||||
widely used where low data rate communications suffice.
|
||||
Since it's also a licensed trademark, some vendors use another
|
||||
name (such as "Two-Wire Interface", TWI) for the same bus.
|
||||
I2C only needs two signals (SCL for clock, SDA for data), conserving
|
||||
board real estate and minimizing signal quality issues.
|
||||
Most I2C devices use seven bit addresses, and bus speeds of up
|
||||
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
|
||||
found wide use.
|
||||
I2C is a multi-master bus; open drain signaling is used to
|
||||
arbitrate between masters, as well as to handshake and to
|
||||
synchronize clocks from slower clients.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The Linux I2C programming interfaces support only the master
|
||||
side of bus interactions, not the slave side.
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
An I2C "Adapter Driver" abstracts the controller hardware; it binds
|
||||
to a physical device (perhaps a PCI device or platform_device) and
|
||||
exposes a <structname>struct i2c_adapter</structname> representing
|
||||
each I2C bus segment it manages.
|
||||
On each I2C bus segment will be I2C devices represented by a
|
||||
<structname>struct i2c_client</structname>. Those devices will
|
||||
be bound to a <structname>struct i2c_driver</structname>,
|
||||
which should follow the standard Linux driver model.
|
||||
(At this writing, a legacy model is more widely used.)
|
||||
There are functions to perform various I2C protocol operations; at
|
||||
this writing all such functions are usable only from task context.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||
systems are also I2C conformant. The electrical constraints are
|
||||
tighter for SMBus, and it standardizes particular protocol messages
|
||||
and idioms. Controllers that support I2C can also support most
|
||||
SMBus operations, but SMBus controllers don't support all the protocol
|
||||
options that an I2C controller will.
|
||||
There are functions to perform various SMBus protocol operations,
|
||||
either using I2C primitives or by issuing SMBus commands to
|
||||
i2c_adapter devices which don't support those I2C operations.
|
||||
</para>
|
||||
|
||||
!Iinclude/linux/i2c.h
|
||||
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
|
||||
!Edrivers/i2c/i2c-core.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="splice">
|
||||
<title>splice API</title>
|
||||
<para>)
|
||||
@@ -654,4 +708,5 @@ X!Idrivers/video/console/fonts.c
|
||||
!Ffs/splice.c
|
||||
</chapter>
|
||||
|
||||
|
||||
</book>
|
||||
|
||||
@@ -330,3 +330,10 @@ Who: Tejun Heo <htejun@gmail.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: Legacy RTC drivers (under drivers/i2c/chips)
|
||||
When: November 2007
|
||||
Why: Obsolete. We have a RTC subsystem with better drivers.
|
||||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ Supported adapters:
|
||||
'810' and '810E' chipsets)
|
||||
* Intel 82801BA (ICH2 - part of the '815E' chipset)
|
||||
* Intel 82801CA/CAM (ICH3)
|
||||
* Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported)
|
||||
* Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
|
||||
* Intel 82801DB (ICH4) (HW PEC supported)
|
||||
* Intel 82801EB/ER (ICH5) (HW PEC supported)
|
||||
* Intel 6300ESB
|
||||
* Intel 82801FB/FR/FW/FRW (ICH6)
|
||||
* Intel 82801G (ICH7)
|
||||
|
||||
@@ -6,7 +6,7 @@ Supported adapters:
|
||||
Datasheet: Publicly available at the Intel website
|
||||
* ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
|
||||
Datasheet: Only available via NDA from ServerWorks
|
||||
* ATI IXP200, IXP300, IXP400 and SB600 southbridges
|
||||
* ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges
|
||||
Datasheet: Not publicly available
|
||||
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
|
||||
Datasheet: Publicly available at the SMSC website http://www.smsc.com
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
Kernel driver i2c-taos-evm
|
||||
|
||||
Author: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This is a driver for the evaluation modules for TAOS I2C/SMBus chips.
|
||||
The modules include an SMBus master with limited capabilities, which can
|
||||
be controlled over the serial port. Virtually all evaluation modules
|
||||
are supported, but a few lines of code need to be added for each new
|
||||
module to instantiate the right I2C chip on the bus. Obviously, a driver
|
||||
for the chip in question is also needed.
|
||||
|
||||
Currently supported devices are:
|
||||
|
||||
* TAOS TSL2550 EVM
|
||||
|
||||
For addtional information on TAOS products, please see
|
||||
http://www.taosinc.com/
|
||||
|
||||
|
||||
Using this driver
|
||||
-----------------
|
||||
|
||||
In order to use this driver, you'll need the serport driver, and the
|
||||
inputattach tool, which is part of the input-utils package. The following
|
||||
commands will tell the kernel that you have a TAOS EVM on the first
|
||||
serial port:
|
||||
|
||||
# modprobe serport
|
||||
# inputattach --taos-evm /dev/ttyS0
|
||||
|
||||
|
||||
Technical details
|
||||
-----------------
|
||||
|
||||
Only 4 SMBus transaction types are supported by the TAOS evaluation
|
||||
modules:
|
||||
* Receive Byte
|
||||
* Send Byte
|
||||
* Read Byte
|
||||
* Write Byte
|
||||
|
||||
The communication protocol is text-based and pretty simple. It is
|
||||
described in a PDF document on the CD which comes with the evaluation
|
||||
module. The communication is rather slow, because the serial port has
|
||||
to operate at 1200 bps. However, I don't think this is a big concern in
|
||||
practice, as these modules are meant for evaluation and testing only.
|
||||
@@ -99,7 +99,7 @@ And then read the data
|
||||
|
||||
or
|
||||
|
||||
count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer);
|
||||
count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
|
||||
|
||||
The block read should read 16 bytes.
|
||||
0x84 is the block read command.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
Kernel driver x1205
|
||||
===================
|
||||
|
||||
Supported chips:
|
||||
* Xicor X1205 RTC
|
||||
Prefix: 'x1205'
|
||||
Addresses scanned: none
|
||||
Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
|
||||
|
||||
Authors:
|
||||
Karen Spearel <kas11@tampabay.rr.com>,
|
||||
Alessandro Zummo <a.zummo@towertech.it>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This module aims to provide complete access to the Xicor X1205 RTC.
|
||||
Recently Xicor has merged with Intersil, but the chip is
|
||||
still sold under the Xicor brand.
|
||||
|
||||
This chip is located at address 0x6f and uses a 2-byte register addressing.
|
||||
Two bytes need to be written to read a single register, while most
|
||||
other chips just require one and take the second one as the data
|
||||
to be written. To prevent corrupting unknown chips, the user must
|
||||
explicitely set the probe parameter.
|
||||
|
||||
example:
|
||||
|
||||
modprobe x1205 probe=0,0x6f
|
||||
|
||||
The module supports one more option, hctosys, which is used to set the
|
||||
software clock from the x1205. On systems where the x1205 is the
|
||||
only hardware rtc, this parameter could be used to achieve a correct
|
||||
date/time earlier in the system boot sequence.
|
||||
|
||||
example:
|
||||
|
||||
modprobe x1205 probe=0,0x6f hctosys=1
|
||||
@@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers
|
||||
Algorithm drivers
|
||||
-----------------
|
||||
|
||||
i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
|
||||
i2c-algo-bit: A bit-banging algorithm
|
||||
i2c-algo-pcf: A PCF 8584 style algorithm
|
||||
i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
|
||||
@@ -81,6 +80,5 @@ i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatch
|
||||
i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
|
||||
i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
|
||||
i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit)
|
||||
i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
|
||||
i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit)
|
||||
|
||||
|
||||
@@ -571,7 +571,7 @@ SMBus communication
|
||||
u8 command, u8 length,
|
||||
u8 *values);
|
||||
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
|
||||
u8 command, u8 *values);
|
||||
u8 command, u8 length, u8 *values);
|
||||
|
||||
These ones were removed in Linux 2.6.10 because they had no users, but could
|
||||
be added back later if needed:
|
||||
|
||||
@@ -34,10 +34,6 @@ config I2C_ALGOPCA
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-algo-pca.
|
||||
|
||||
config I2C_ALGO8XX
|
||||
tristate "MPC8xx CPM I2C interface"
|
||||
depends on 8xx
|
||||
|
||||
config I2C_ALGO_SGI
|
||||
tristate "I2C SGI interfaces"
|
||||
depends on SGI_IP22 || SGI_IP32 || X86_VISWS
|
||||
|
||||
@@ -207,6 +207,7 @@ config I2C_PIIX4
|
||||
ATI IXP300
|
||||
ATI IXP400
|
||||
ATI SB600
|
||||
ATI SB700
|
||||
Serverworks OSB4
|
||||
Serverworks CSB5
|
||||
Serverworks CSB6
|
||||
@@ -390,11 +391,6 @@ config I2C_PROSAVAGE
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-prosavage.
|
||||
|
||||
config I2C_RPXLITE
|
||||
tristate "Embedded Planet RPX Lite/Classic support"
|
||||
depends on RPXLITE || RPXCLASSIC
|
||||
select I2C_ALGO8XX
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on ARCH_S3C2410
|
||||
@@ -512,6 +508,22 @@ config I2C_SIS96X
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis96x.
|
||||
|
||||
config I2C_TAOS_EVM
|
||||
tristate "TAOS evaluation module"
|
||||
depends on EXPERIMENTAL
|
||||
select SERIO
|
||||
select SERIO_SERPORT
|
||||
default n
|
||||
help
|
||||
This supports TAOS evaluation modules on serial port. In order to
|
||||
use this driver, you will need the inputattach tool, which is part
|
||||
of the input-utils package.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-taos-evm.
|
||||
|
||||
config I2C_STUB
|
||||
tristate "I2C/SMBus Test Stub"
|
||||
depends on EXPERIMENTAL && m
|
||||
@@ -635,4 +647,13 @@ config I2C_PNX
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pnx.
|
||||
|
||||
config I2C_PMCMSP
|
||||
tristate "PMC MSP I2C TWI Controller"
|
||||
depends on PMC_MSP
|
||||
help
|
||||
This driver supports the PMC TWI controller on MSP devices.
|
||||
|
||||
This driver can also be built as module. If so, the module
|
||||
will be called i2c-pmcmsp.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -32,10 +32,10 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
|
||||
obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
|
||||
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
||||
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
|
||||
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
@@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
|
||||
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
|
||||
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
|
||||
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
|
||||
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
|
||||
|
||||
@@ -63,14 +63,14 @@ static void i2c_gpio_setscl_val(void *data, int state)
|
||||
gpio_set_value(pdata->scl_pin, state);
|
||||
}
|
||||
|
||||
int i2c_gpio_getsda(void *data)
|
||||
static int i2c_gpio_getsda(void *data)
|
||||
{
|
||||
struct i2c_gpio_platform_data *pdata = data;
|
||||
|
||||
return gpio_get_value(pdata->sda_pin);
|
||||
}
|
||||
|
||||
int i2c_gpio_getscl(void *data)
|
||||
static int i2c_gpio_getscl(void *data)
|
||||
{
|
||||
struct i2c_gpio_platform_data *pdata = data;
|
||||
|
||||
@@ -142,7 +142,13 @@ static int __init i2c_gpio_probe(struct platform_device *pdev)
|
||||
adap->algo_data = bit_data;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
||||
ret = i2c_bit_add_bus(adap);
|
||||
/*
|
||||
* If "dev->id" is negative we consider it as zero.
|
||||
* The reason to do so is to avoid sysfs names that only make
|
||||
* sense when there are multiple adapters.
|
||||
*/
|
||||
adap->nr = pdev->id >= 0 ? pdev->id : 0;
|
||||
ret = i2c_bit_add_numbered_bus(adap);
|
||||
if (ret)
|
||||
goto err_add_bus;
|
||||
|
||||
|
||||
+166
-83
@@ -22,12 +22,12 @@
|
||||
|
||||
/*
|
||||
SUPPORTED DEVICES PCI ID
|
||||
82801AA 2413
|
||||
82801AB 2423
|
||||
82801BA 2443
|
||||
82801CA/CAM 2483
|
||||
82801DB 24C3 (HW PEC supported, 32 byte buffer not supported)
|
||||
82801EB 24D3 (HW PEC supported, 32 byte buffer not supported)
|
||||
82801AA 2413
|
||||
82801AB 2423
|
||||
82801BA 2443
|
||||
82801CA/CAM 2483
|
||||
82801DB 24C3 (HW PEC supported)
|
||||
82801EB 24D3 (HW PEC supported)
|
||||
6300ESB 25A4
|
||||
ICH6 266A
|
||||
ICH7 27DA
|
||||
@@ -74,6 +74,13 @@
|
||||
#define SMBHSTCFG_SMB_SMI_EN 2
|
||||
#define SMBHSTCFG_I2C_EN 4
|
||||
|
||||
/* Auxillary control register bits, ICH4+ only */
|
||||
#define SMBAUXCTL_CRC 1
|
||||
#define SMBAUXCTL_E32B 2
|
||||
|
||||
/* kill bit for SMBHSTCNT */
|
||||
#define SMBHSTCNT_KILL 2
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_TIMEOUT 100
|
||||
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
|
||||
@@ -91,10 +98,15 @@
|
||||
#define I801_START 0x40
|
||||
#define I801_PEC_EN 0x80 /* ICH4 only */
|
||||
|
||||
|
||||
static int i801_transaction(void);
|
||||
static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
int command, int hwpec);
|
||||
/* I801 Hosts Status register bits */
|
||||
#define SMBHSTSTS_BYTE_DONE 0x80
|
||||
#define SMBHSTSTS_INUSE_STS 0x40
|
||||
#define SMBHSTSTS_SMBALERT_STS 0x20
|
||||
#define SMBHSTSTS_FAILED 0x10
|
||||
#define SMBHSTSTS_BUS_ERR 0x08
|
||||
#define SMBHSTSTS_DEV_ERR 0x04
|
||||
#define SMBHSTSTS_INTR 0x02
|
||||
#define SMBHSTSTS_HOST_BUSY 0x01
|
||||
|
||||
static unsigned long i801_smba;
|
||||
static unsigned char i801_original_hstcfg;
|
||||
@@ -102,7 +114,7 @@ static struct pci_driver i801_driver;
|
||||
static struct pci_dev *I801_dev;
|
||||
static int isich4;
|
||||
|
||||
static int i801_transaction(void)
|
||||
static int i801_transaction(int xact)
|
||||
{
|
||||
int temp;
|
||||
int result = 0;
|
||||
@@ -127,33 +139,40 @@ static int i801_transaction(void)
|
||||
}
|
||||
}
|
||||
|
||||
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
|
||||
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
|
||||
* INTREN, SMBSCMD are passed in xact */
|
||||
outb_p(xact | I801_START, SMBHSTCNT);
|
||||
|
||||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
|
||||
} while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
|
||||
result = -1;
|
||||
/* try to stop the current command */
|
||||
dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
|
||||
outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
|
||||
msleep(1);
|
||||
outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
if (temp & SMBHSTSTS_FAILED) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
if (temp & 0x08) {
|
||||
if (temp & SMBHSTSTS_BUS_ERR) {
|
||||
result = -1;
|
||||
dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
|
||||
"until next hard reset. (sorry!)\n");
|
||||
/* Clock stops and slave is stuck in mid-transmission */
|
||||
}
|
||||
|
||||
if (temp & 0x04) {
|
||||
if (temp & SMBHSTSTS_DEV_ERR) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: no response!\n");
|
||||
}
|
||||
@@ -172,44 +191,70 @@ static int i801_transaction(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* All-inclusive block transaction function */
|
||||
static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
int command, int hwpec)
|
||||
/* wait for INTR bit as advised by Intel */
|
||||
static void i801_wait_hwpec(void)
|
||||
{
|
||||
int timeout = 0;
|
||||
int temp;
|
||||
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
} while ((!(temp & SMBHSTSTS_INTR))
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
|
||||
}
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
}
|
||||
|
||||
static int i801_block_transaction_by_block(union i2c_smbus_data *data,
|
||||
char read_write, int hwpec)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
inb_p(SMBHSTCNT); /* reset the data buffer index */
|
||||
|
||||
/* Use 32-byte buffer to process this transaction */
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
outb_p(len, SMBHSTDAT0);
|
||||
for (i = 0; i < len; i++)
|
||||
outb_p(data->block[i+1], SMBBLKDAT);
|
||||
}
|
||||
|
||||
if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
|
||||
I801_PEC_EN * hwpec))
|
||||
return -1;
|
||||
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
len = inb_p(SMBHSTDAT0);
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -1;
|
||||
|
||||
data->block[0] = len;
|
||||
for (i = 0; i < len; i++)
|
||||
data->block[i + 1] = inb_p(SMBBLKDAT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
|
||||
char read_write, int hwpec)
|
||||
{
|
||||
int i, len;
|
||||
int smbcmd;
|
||||
int temp;
|
||||
int result = 0;
|
||||
int timeout;
|
||||
unsigned char hostc, errmask;
|
||||
unsigned char errmask;
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
/* set I2C_EN bit in configuration register */
|
||||
pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
|
||||
pci_write_config_byte(I801_dev, SMBHSTCFG,
|
||||
hostc | SMBHSTCFG_I2C_EN);
|
||||
} else {
|
||||
dev_err(&I801_dev->dev,
|
||||
"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
len = data->block[0];
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if (len < 1)
|
||||
len = 1;
|
||||
if (len > 32)
|
||||
len = 32;
|
||||
outb_p(len, SMBHSTDAT0);
|
||||
outb_p(data->block[1], SMBBLKDAT);
|
||||
} else {
|
||||
len = 32; /* max for reads */
|
||||
}
|
||||
|
||||
if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
/* set 32 byte buffer */
|
||||
}
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
@@ -227,13 +272,13 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
/* Make sure the SMBus host is ready to start transmitting */
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
if (i == 1) {
|
||||
/* Erronenous conditions before transaction:
|
||||
/* Erronenous conditions before transaction:
|
||||
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
|
||||
errmask=0x9f;
|
||||
errmask = 0x9f;
|
||||
} else {
|
||||
/* Erronenous conditions during transaction:
|
||||
/* Erronenous conditions during transaction:
|
||||
* Failed, Bus_Err, Dev_Err, Intr */
|
||||
errmask=0x1e;
|
||||
errmask = 0x1e;
|
||||
}
|
||||
if (temp & errmask) {
|
||||
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
|
||||
@@ -242,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
|
||||
dev_err(&I801_dev->dev,
|
||||
"Reset failed! (%02x)\n", temp);
|
||||
result = -1;
|
||||
goto END;
|
||||
return -1;
|
||||
}
|
||||
if (i != 1) {
|
||||
if (i != 1)
|
||||
/* if die in middle of block transaction, fail */
|
||||
result = -1;
|
||||
goto END;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
@@ -261,33 +303,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
}
|
||||
while ((!(temp & 0x80))
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
while ((!(temp & SMBHSTSTS_BYTE_DONE))
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
/* try to stop the current command */
|
||||
dev_dbg(&I801_dev->dev, "Terminating the current "
|
||||
"operation\n");
|
||||
outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
|
||||
msleep(1);
|
||||
outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL),
|
||||
SMBHSTCNT);
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
if (temp & SMBHSTSTS_FAILED) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev,
|
||||
"Error: Failed bus transaction\n");
|
||||
} else if (temp & 0x08) {
|
||||
} else if (temp & SMBHSTSTS_BUS_ERR) {
|
||||
result = -1;
|
||||
dev_err(&I801_dev->dev, "Bus collision!\n");
|
||||
} else if (temp & 0x04) {
|
||||
} else if (temp & SMBHSTSTS_DEV_ERR) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: no response!\n");
|
||||
}
|
||||
|
||||
if (i == 1 && read_write == I2C_SMBUS_READ) {
|
||||
len = inb_p(SMBHSTDAT0);
|
||||
if (len < 1)
|
||||
len = 1;
|
||||
if (len > 32)
|
||||
len = 32;
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -1;
|
||||
data->block[0] = len;
|
||||
}
|
||||
|
||||
@@ -310,25 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
|
||||
|
||||
if (result < 0)
|
||||
goto END;
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (hwpec) {
|
||||
/* wait for INTR bit as advised by Intel */
|
||||
timeout = 0;
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
} while ((!(temp & 0x02))
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
static int i801_set_block_buffer_mode(void)
|
||||
{
|
||||
outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
|
||||
if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
|
||||
/* Block transaction function */
|
||||
static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||
int command, int hwpec)
|
||||
{
|
||||
int result = 0;
|
||||
unsigned char hostc;
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
/* set I2C_EN bit in configuration register */
|
||||
pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
|
||||
pci_write_config_byte(I801_dev, SMBHSTCFG,
|
||||
hostc | SMBHSTCFG_I2C_EN);
|
||||
} else {
|
||||
dev_err(&I801_dev->dev,
|
||||
"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
|
||||
return -1;
|
||||
}
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
}
|
||||
result = 0;
|
||||
END:
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
if (data->block[0] < 1)
|
||||
data->block[0] = 1;
|
||||
if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
|
||||
data->block[0] = I2C_SMBUS_BLOCK_MAX;
|
||||
} else {
|
||||
data->block[0] = 32; /* max for reads */
|
||||
}
|
||||
|
||||
if (isich4 && i801_set_block_buffer_mode() == 0 )
|
||||
result = i801_block_transaction_by_block(data, read_write,
|
||||
hwpec);
|
||||
else
|
||||
result = i801_block_transaction_byte_by_byte(data, read_write,
|
||||
hwpec);
|
||||
|
||||
if (result == 0 && hwpec)
|
||||
i801_wait_hwpec();
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
/* restore saved configuration register value */
|
||||
pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
|
||||
@@ -393,19 +473,22 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */
|
||||
if (hwpec) /* enable/disable hardware PEC */
|
||||
outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
|
||||
else
|
||||
outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
|
||||
|
||||
if(block)
|
||||
ret = i801_block_transaction(data, read_write, size, hwpec);
|
||||
else {
|
||||
outb_p(xact | ENABLE_INT9, SMBHSTCNT);
|
||||
ret = i801_transaction();
|
||||
}
|
||||
else
|
||||
ret = i801_transaction(xact | ENABLE_INT9);
|
||||
|
||||
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
|
||||
time, so we forcibly disable it after every transaction. */
|
||||
time, so we forcibly disable it after every transaction. Turn off
|
||||
E32B for the same reason. */
|
||||
if (hwpec)
|
||||
outb_p(0, SMBAUXCTL);
|
||||
outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
|
||||
SMBAUXCTL);
|
||||
|
||||
if(block)
|
||||
return ret;
|
||||
|
||||
@@ -491,6 +491,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
|
||||
new_adapter->id = I2C_HW_IOP3XX;
|
||||
new_adapter->owner = THIS_MODULE;
|
||||
new_adapter->dev.parent = &pdev->dev;
|
||||
new_adapter->nr = pdev->id;
|
||||
|
||||
/*
|
||||
* Default values...should these come in from board code?
|
||||
@@ -508,7 +509,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, new_adapter);
|
||||
new_adapter->algo_data = adapter_data;
|
||||
|
||||
i2c_add_adapter(new_adapter);
|
||||
i2c_add_numbered_adapter(new_adapter);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -74,6 +74,25 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
|
||||
* the bus, because it wants to send ACK.
|
||||
* Following sequence of enabling/disabling and sending start/stop generates
|
||||
* the pulse, so it's all OK.
|
||||
*/
|
||||
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
|
||||
{
|
||||
writeccr(i2c, 0);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MEN);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MSTA | CCR_MTX);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
|
||||
udelay(30);
|
||||
writeccr(i2c, CCR_MEN);
|
||||
udelay(30);
|
||||
}
|
||||
|
||||
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
|
||||
{
|
||||
unsigned long orig_jiffies = jiffies;
|
||||
@@ -153,6 +172,7 @@ static void mpc_i2c_start(struct mpc_i2c *i2c)
|
||||
static void mpc_i2c_stop(struct mpc_i2c *i2c)
|
||||
{
|
||||
writeccr(i2c, CCR_MEN);
|
||||
writeccr(i2c, 0);
|
||||
}
|
||||
|
||||
static int mpc_write(struct mpc_i2c *i2c, int target,
|
||||
@@ -245,6 +265,9 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
}
|
||||
if (time_after(jiffies, orig_jiffies + HZ)) {
|
||||
pr_debug("I2C: timeout\n");
|
||||
if (readb(i2c->base + MPC_I2C_SR) ==
|
||||
(CSR_MCF | CSR_MBB | CSR_RXAK))
|
||||
mpc_i2c_fixup(i2c);
|
||||
return -EIO;
|
||||
}
|
||||
schedule();
|
||||
@@ -327,9 +350,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
i2c->adap = mpc_ops;
|
||||
i2c->adap.nr = pdev->id;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
|
||||
if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
|
||||
printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
|
||||
goto fail_add;
|
||||
}
|
||||
|
||||
@@ -527,6 +527,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON;
|
||||
drv_data->adapter.timeout = pdata->timeout;
|
||||
drv_data->adapter.retries = pdata->retries;
|
||||
drv_data->adapter.nr = pd->id;
|
||||
platform_set_drvdata(pd, drv_data);
|
||||
i2c_set_adapdata(&drv_data->adapter, drv_data);
|
||||
|
||||
@@ -539,7 +540,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
drv_data->irq);
|
||||
rc = -EINVAL;
|
||||
goto exit_unmap_regs;
|
||||
} else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) {
|
||||
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
|
||||
dev_err(&drv_data->adapter.dev,
|
||||
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
|
||||
goto exit_free_irq;
|
||||
|
||||
@@ -61,6 +61,7 @@ struct nforce2_smbus {
|
||||
struct i2c_adapter adapter;
|
||||
int base;
|
||||
int size;
|
||||
int blockops;
|
||||
};
|
||||
|
||||
|
||||
@@ -80,6 +81,8 @@ struct nforce2_smbus {
|
||||
#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
|
||||
#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
|
||||
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
|
||||
#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
|
||||
bytes */
|
||||
|
||||
#define NVIDIA_SMB_STS_DONE 0x80
|
||||
#define NVIDIA_SMB_STS_ALRM 0x40
|
||||
@@ -92,6 +95,7 @@ struct nforce2_smbus {
|
||||
#define NVIDIA_SMB_PRTCL_BYTE 0x04
|
||||
#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
|
||||
#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
|
||||
#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
|
||||
#define NVIDIA_SMB_PRTCL_PEC 0x80
|
||||
|
||||
static struct pci_driver nforce2_driver;
|
||||
@@ -103,6 +107,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
||||
{
|
||||
struct nforce2_smbus *smbus = adap->algo_data;
|
||||
unsigned char protocol, pec, temp;
|
||||
u8 len;
|
||||
int i;
|
||||
|
||||
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
|
||||
NVIDIA_SMB_PRTCL_WRITE;
|
||||
@@ -137,6 +143,25 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
||||
protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
outb_p(command, NVIDIA_SMB_CMD);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
|
||||
dev_err(&adap->dev,
|
||||
"Transaction failed "
|
||||
"(requested block size: %d)\n",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
outb_p(len, NVIDIA_SMB_BCNT);
|
||||
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
|
||||
outb_p(data->block[i + 1],
|
||||
NVIDIA_SMB_DATA+i);
|
||||
}
|
||||
protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
@@ -174,6 +199,14 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
len = inb_p(NVIDIA_SMB_BCNT);
|
||||
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
|
||||
for (i = 0; i < len; i++)
|
||||
data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
|
||||
data->block[0] = len;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -184,7 +217,9 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
/* other functionality might be possible, but is not tested */
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
(((struct nforce2_smbus*)adapter->algo_data)->blockops ?
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA : 0);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
@@ -268,6 +303,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
|
||||
return -ENOMEM;
|
||||
pci_set_drvdata(dev, smbuses);
|
||||
|
||||
switch(dev->device) {
|
||||
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
|
||||
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
|
||||
smbuses[0].blockops = 1;
|
||||
smbuses[1].blockops = 1;
|
||||
}
|
||||
|
||||
/* SMBus adapter 1 */
|
||||
res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
|
||||
if (res1 < 0) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
Supports:
|
||||
Intel PIIX4, 440MX
|
||||
Serverworks OSB4, CSB5, CSB6, HT-1000
|
||||
ATI IXP200, IXP300, IXP400, SB600
|
||||
ATI IXP200, IXP300, IXP400, SB600, SB700
|
||||
SMSC Victory66
|
||||
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
@@ -399,6 +399,8 @@ static struct pci_device_id piix4_ids[] = {
|
||||
.driver_data = 0 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
|
||||
.driver_data = 0 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS),
|
||||
.driver_data = 0 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
|
||||
.driver_data = 0 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user