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: (56 commits) i2c: Add detection capability to new-style drivers i2c: Call client_unregister for new-style devices too i2c: Clean up old chip drivers i2c-ibm_iic: Register child nodes i2c: New-style EEPROM driver using device IDs i2c: Export the i2c_bus_type symbol i2c-au1550: Fix PM support i2c-dev: Delete empty detach_client callback i2c: Drop stray references to lm_sensors i2c: Check for ACPI resource conflicts i2c-ocores: basic PM support i2c-sibyte: SWARM I2C board initialization i2c-i801: Fix handling of error conditions i2c-i801: Rename local variable temp to status i2c-i801: Properly report bus arbitration loss i2c-i801: Remove verbose debugging messages i2c-algo-pcf: Drop unused struct members i2c-algo-pcf: Multi-master lost-arbitration improvement i2c: Deprecate the legacy gpio drivers i2c-pxa: Initialize early ...
This commit is contained in:
commit
dc221eae08
|
@ -222,13 +222,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: i2c-i810, i2c-prosavage and i2c-savage4
|
||||
When: May 2008
|
||||
Why: These drivers are superseded by i810fb, intelfb and savagefb.
|
||||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What (Why):
|
||||
- include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files
|
||||
(superseded by xt_TOS/xt_tos target & match)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
Kernel driver i2c-i810
|
||||
|
||||
Supported adapters:
|
||||
* Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH)
|
||||
* Intel 82845G (GMCH)
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Ralph Metzler <rjkm@thp.uni-koeln.de>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Main contact: Mark Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
WARNING: If you have an '810' or '815' motherboard, your standard I2C
|
||||
temperature sensors are most likely on the 801's I2C bus. You want the
|
||||
i2c-i801 driver for those, not this driver.
|
||||
|
||||
Now for the i2c-i810...
|
||||
|
||||
The GMCH chip contains two I2C interfaces.
|
||||
|
||||
The first interface is used for DDC (Data Display Channel) which is a
|
||||
serial channel through the VGA monitor connector to a DDC-compliant
|
||||
monitor. This interface is defined by the Video Electronics Standards
|
||||
Association (VESA). The standards are available for purchase at
|
||||
http://www.vesa.org .
|
||||
|
||||
The second interface is a general-purpose I2C bus. It may be connected to a
|
||||
TV-out chip such as the BT869 or possibly to a digital flat-panel display.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Both busses use the i2c-algo-bit driver for 'bit banging'
|
||||
and support for specific transactions is provided by i2c-algo-bit.
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1),
|
||||
the test may fail; if so, the i2c-i810 driver won't be inserted. However,
|
||||
we think this has been fixed.
|
|
@ -1,23 +0,0 @@
|
|||
Kernel driver i2c-prosavage
|
||||
|
||||
Supported adapters:
|
||||
|
||||
S3/VIA KM266/VT8375 aka ProSavage8
|
||||
S3/VIA KM133/VT8365 aka Savage4
|
||||
|
||||
Author: Henk Vergonet <henk@god.dyndns.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or
|
||||
'host').
|
||||
|
||||
The first interface is used for DDC (Data Display Channel) which is a
|
||||
serial channel through the VGA monitor connector to a DDC-compliant
|
||||
monitor. This interface is defined by the Video Electronics Standards
|
||||
Association (VESA). The standards are available for purchase at
|
||||
http://www.vesa.org . The second interface is a general-purpose I2C bus.
|
||||
|
||||
Usefull for gaining access to the TV Encoder chips.
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
Kernel driver i2c-savage4
|
||||
|
||||
Supported adapters:
|
||||
* Savage4
|
||||
* Savage2000
|
||||
|
||||
Authors:
|
||||
Alexander Wold <awold@bigfoot.com>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The Savage4 chips contain two I2C interfaces (aka a I2C 'master'
|
||||
or 'host').
|
||||
|
||||
The first interface is used for DDC (Data Display Channel) which is a
|
||||
serial channel through the VGA monitor connector to a DDC-compliant
|
||||
monitor. This interface is defined by the Video Electronics Standards
|
||||
Association (VESA). The standards are available for purchase at
|
||||
http://www.vesa.org . The DDC bus is not yet supported because its register
|
||||
is not directly memory-mapped.
|
||||
|
||||
The second interface is a general-purpose I2C bus. This is the only
|
||||
interface supported by the driver at the moment.
|
||||
|
127
Documentation/i2c/fault-codes
Normal file
127
Documentation/i2c/fault-codes
Normal file
|
@ -0,0 +1,127 @@
|
|||
This is a summary of the most important conventions for use of fault
|
||||
codes in the I2C/SMBus stack.
|
||||
|
||||
|
||||
A "Fault" is not always an "Error"
|
||||
----------------------------------
|
||||
Not all fault reports imply errors; "page faults" should be a familiar
|
||||
example. Software often retries idempotent operations after transient
|
||||
faults. There may be fancier recovery schemes that are appropriate in
|
||||
some cases, such as re-initializing (and maybe resetting). After such
|
||||
recovery, triggered by a fault report, there is no error.
|
||||
|
||||
In a similar way, sometimes a "fault" code just reports one defined
|
||||
result for an operation ... it doesn't indicate that anything is wrong
|
||||
at all, just that the outcome wasn't on the "golden path".
|
||||
|
||||
In short, your I2C driver code may need to know these codes in order
|
||||
to respond correctly. Other code may need to rely on YOUR code reporting
|
||||
the right fault code, so that it can (in turn) behave correctly.
|
||||
|
||||
|
||||
I2C and SMBus fault codes
|
||||
-------------------------
|
||||
These are returned as negative numbers from most calls, with zero or
|
||||
some positive number indicating a non-fault return. The specific
|
||||
numbers associated with these symbols differ between architectures,
|
||||
though most Linux systems use <asm-generic/errno*.h> numbering.
|
||||
|
||||
Note that the descriptions here are not exhaustive. There are other
|
||||
codes that may be returned, and other cases where these codes should
|
||||
be returned. However, drivers should not return other codes for these
|
||||
cases (unless the hardware doesn't provide unique fault reports).
|
||||
|
||||
Also, codes returned by adapter probe methods follow rules which are
|
||||
specific to their host bus (such as PCI, or the platform bus).
|
||||
|
||||
|
||||
EAGAIN
|
||||
Returned by I2C adapters when they lose arbitration in master
|
||||
transmit mode: some other master was transmitting different
|
||||
data at the same time.
|
||||
|
||||
Also returned when trying to invoke an I2C operation in an
|
||||
atomic context, when some task is already using that I2C bus
|
||||
to execute some other operation.
|
||||
|
||||
EBADMSG
|
||||
Returned by SMBus logic when an invalid Packet Error Code byte
|
||||
is received. This code is a CRC covering all bytes in the
|
||||
transaction, and is sent before the terminating STOP. This
|
||||
fault is only reported on read transactions; the SMBus slave
|
||||
may have a way to report PEC mismatches on writes from the
|
||||
host. Note that even if PECs are in use, you should not rely
|
||||
on these as the only way to detect incorrect data transfers.
|
||||
|
||||
EBUSY
|
||||
Returned by SMBus adapters when the bus was busy for longer
|
||||
than allowed. This usually indicates some device (maybe the
|
||||
SMBus adapter) needs some fault recovery (such as resetting),
|
||||
or that the reset was attempted but failed.
|
||||
|
||||
EINVAL
|
||||
This rather vague error means an invalid parameter has been
|
||||
detected before any I/O operation was started. Use a more
|
||||
specific fault code when you can.
|
||||
|
||||
One example would be a driver trying an SMBus Block Write
|
||||
with block size outside the range of 1-32 bytes.
|
||||
|
||||
EIO
|
||||
This rather vague error means something went wrong when
|
||||
performing an I/O operation. Use a more specific fault
|
||||
code when you can.
|
||||
|
||||
ENODEV
|
||||
Returned by driver probe() methods. This is a bit more
|
||||
specific than ENXIO, implying the problem isn't with the
|
||||
address, but with the device found there. Driver probes
|
||||
may verify the device returns *correct* responses, and
|
||||
return this as appropriate. (The driver core will warn
|
||||
about probe faults other than ENXIO and ENODEV.)
|
||||
|
||||
ENOMEM
|
||||
Returned by any component that can't allocate memory when
|
||||
it needs to do so.
|
||||
|
||||
ENXIO
|
||||
Returned by I2C adapters to indicate that the address phase
|
||||
of a transfer didn't get an ACK. While it might just mean
|
||||
an I2C device was temporarily not responding, usually it
|
||||
means there's nothing listening at that address.
|
||||
|
||||
Returned by driver probe() methods to indicate that they
|
||||
found no device to bind to. (ENODEV may also be used.)
|
||||
|
||||
EOPNOTSUPP
|
||||
Returned by an adapter when asked to perform an operation
|
||||
that it doesn't, or can't, support.
|
||||
|
||||
For example, this would be returned when an adapter that
|
||||
doesn't support SMBus block transfers is asked to execute
|
||||
one. In that case, the driver making that request should
|
||||
have verified that functionality was supported before it
|
||||
made that block transfer request.
|
||||
|
||||
Similarly, if an I2C adapter can't execute all legal I2C
|
||||
messages, it should return this when asked to perform a
|
||||
transaction it can't. (These limitations can't be seen in
|
||||
the adapter's functionality mask, since the assumption is
|
||||
that if an adapter supports I2C it supports all of I2C.)
|
||||
|
||||
EPROTO
|
||||
Returned when slave does not conform to the relevant I2C
|
||||
or SMBus (or chip-specific) protocol specifications. One
|
||||
case is when the length of an SMBus block data response
|
||||
(from the SMBus slave) is outside the range 1-32 bytes.
|
||||
|
||||
ETIMEDOUT
|
||||
This is returned by drivers when an operation took too much
|
||||
time, and was aborted before it completed.
|
||||
|
||||
SMBus adapters may return it when an operation took more
|
||||
time than allowed by the SMBus specification; for example,
|
||||
when a slave stretches clocks too far. I2C has no such
|
||||
timeouts, but it's normal for I2C adapters to impose some
|
||||
arbitrary limits (much longer than SMBus!) too.
|
||||
|
|
@ -42,8 +42,8 @@ Count (8 bits): A data byte containing the length of a block operation.
|
|||
[..]: Data sent by I2C device, as opposed to data sent by the host adapter.
|
||||
|
||||
|
||||
SMBus Quick Command: i2c_smbus_write_quick()
|
||||
=============================================
|
||||
SMBus Quick Command
|
||||
===================
|
||||
|
||||
This sends a single bit to the device, at the place of the Rd/Wr bit.
|
||||
|
||||
|
|
|
@ -44,6 +44,10 @@ static struct i2c_driver foo_driver = {
|
|||
.id_table = foo_ids,
|
||||
.probe = foo_probe,
|
||||
.remove = foo_remove,
|
||||
/* if device autodetection is needed: */
|
||||
.class = I2C_CLASS_SOMETHING,
|
||||
.detect = foo_detect,
|
||||
.address_data = &addr_data,
|
||||
|
||||
/* else, driver uses "legacy" binding model: */
|
||||
.attach_adapter = foo_attach_adapter,
|
||||
|
@ -217,6 +221,31 @@ in the I2C bus driver. You may want to save the returned i2c_client
|
|||
reference for later use.
|
||||
|
||||
|
||||
Device Detection (Standard driver model)
|
||||
----------------------------------------
|
||||
|
||||
Sometimes you do not know in advance which I2C devices are connected to
|
||||
a given I2C bus. This is for example the case of hardware monitoring
|
||||
devices on a PC's SMBus. In that case, you may want to let your driver
|
||||
detect supported devices automatically. This is how the legacy model
|
||||
was working, and is now available as an extension to the standard
|
||||
driver model (so that we can finally get rid of the legacy model.)
|
||||
|
||||
You simply have to define a detect callback which will attempt to
|
||||
identify supported devices (returning 0 for supported ones and -ENODEV
|
||||
for unsupported ones), a list of addresses to probe, and a device type
|
||||
(or class) so that only I2C buses which may have that type of device
|
||||
connected (and not otherwise enumerated) will be probed. The i2c
|
||||
core will then call you back as needed and will instantiate a device
|
||||
for you for every successful detection.
|
||||
|
||||
Note that this mechanism is purely optional and not suitable for all
|
||||
devices. You need some reliable way to identify the supported devices
|
||||
(typically using device-specific, dedicated identification registers),
|
||||
otherwise misdetections are likely to occur and things can get wrong
|
||||
quickly.
|
||||
|
||||
|
||||
Device Deletion (Standard driver model)
|
||||
---------------------------------------
|
||||
|
||||
|
@ -569,7 +598,6 @@ SMBus communication
|
|||
in terms of it. Never use this function directly!
|
||||
|
||||
|
||||
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_read_byte(struct i2c_client * client);
|
||||
extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command);
|
||||
|
@ -578,30 +606,31 @@ SMBus communication
|
|||
extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
|
||||
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
|
||||
u8 command, u16 value);
|
||||
extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
|
||||
u8 command, u8 *values);
|
||||
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
|
||||
u8 command, u8 length,
|
||||
u8 *values);
|
||||
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
|
||||
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:
|
||||
|
||||
extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
|
||||
u8 command, u8 *values);
|
||||
extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
|
||||
u8 command, u8 length,
|
||||
u8 *values);
|
||||
|
||||
These ones were removed from i2c-core because they had no users, but could
|
||||
be added back later if needed:
|
||||
|
||||
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_process_call(struct i2c_client * client,
|
||||
u8 command, u16 value);
|
||||
extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
|
||||
u8 command, u8 length,
|
||||
u8 *values)
|
||||
|
||||
All these transactions return -1 on failure. The 'write' transactions
|
||||
return 0 on success; the 'read' transactions return the read value, except
|
||||
for read_block, which returns the number of values read. The block buffers
|
||||
need not be longer than 32 bytes.
|
||||
All these transactions return a negative errno value on failure. The 'write'
|
||||
transactions return 0 on success; the 'read' transactions return the read
|
||||
value, except for block transactions, which return the number of values
|
||||
read. The block buffers need not be longer than 32 bytes.
|
||||
|
||||
You can read the file `smbus-protocol' for more information about the
|
||||
actual SMBus protocol.
|
||||
|
|
|
@ -1686,6 +1686,13 @@ L: linuxppc-embedded@ozlabs.org
|
|||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
FREESCALE I2C CPM DRIVER
|
||||
P: Jochen Friedrich
|
||||
M: jochen@scram.de
|
||||
L: linuxppc-dev@ozlabs.org
|
||||
L: i2c@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
FREESCALE SOC FS_ENET DRIVER
|
||||
P: Pantelis Antoniou
|
||||
M: pantelis.antoniou@gmail.com
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
obj-y := setup.o rtc_xicor1241.o rtc_m41t81.o
|
||||
|
||||
obj-$(CONFIG_I2C_BOARDINFO) += swarm-i2c.o
|
||||
obj-$(CONFIG_KGDB) += dbg_io.o
|
||||
|
|
37
arch/mips/sibyte/swarm/swarm-i2c.c
Normal file
37
arch/mips/sibyte/swarm/swarm-i2c.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* arch/mips/sibyte/swarm/swarm-i2c.c
|
||||
*
|
||||
* Broadcom BCM91250A (SWARM), etc. I2C platform setup.
|
||||
*
|
||||
* Copyright (c) 2008 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
|
||||
static struct i2c_board_info swarm_i2c_info1[] __initdata = {
|
||||
{
|
||||
I2C_BOARD_INFO("m41t81", 0x68),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init swarm_i2c_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_register_board_info(1, swarm_i2c_info1,
|
||||
ARRAY_SIZE(swarm_i2c_info1));
|
||||
if (err < 0)
|
||||
printk(KERN_ERR
|
||||
"swarm-i2c: cannot register board I2C devices\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
arch_initcall(swarm_i2c_init);
|
|
@ -320,7 +320,7 @@ static int try_address(struct i2c_adapter *i2c_adap,
|
|||
unsigned char addr, int retries)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
int i, ret = -1;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i <= retries; i++) {
|
||||
ret = i2c_outb(i2c_adap, addr);
|
||||
|
@ -508,7 +508,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
addr ^= 1;
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret != 1) && !nak_ok)
|
||||
return -EREMOTEIO;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -182,7 +182,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
|
|||
}
|
||||
if (state != 0xf8) {
|
||||
dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state);
|
||||
return -EIO;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
DEB1("{{{ XFER %d messages\n", num);
|
||||
|
|
|
@ -78,6 +78,36 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap)
|
|||
set_pcf(adap, 1, I2C_PCF_STOP);
|
||||
}
|
||||
|
||||
static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
|
||||
{
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
|
||||
*status));
|
||||
|
||||
/* Cleanup from LAB -- reset and enable ESO.
|
||||
* This resets the PCF8584; since we've lost the bus, no
|
||||
* further attempts should be made by callers to clean up
|
||||
* (no i2c_stop() etc.)
|
||||
*/
|
||||
set_pcf(adap, 1, I2C_PCF_PIN);
|
||||
set_pcf(adap, 1, I2C_PCF_ESO);
|
||||
|
||||
/* We pause for a time period sufficient for any running
|
||||
* I2C transaction to complete -- the arbitration logic won't
|
||||
* work properly until the next START is seen.
|
||||
* It is assumed the bus driver or client has set a proper value.
|
||||
*
|
||||
* REVISIT: should probably use msleep instead of mdelay if we
|
||||
* know we can sleep.
|
||||
*/
|
||||
if (adap->lab_mdelay)
|
||||
mdelay(adap->lab_mdelay);
|
||||
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
|
||||
get_pcf(adap, 1)));
|
||||
}
|
||||
|
||||
static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
|
||||
|
||||
int timeout = DEF_TIMEOUT;
|
||||
|
@ -109,23 +139,7 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
|
|||
*status = get_pcf(adap, 1);
|
||||
}
|
||||
if (*status & I2C_PCF_LAB) {
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
|
||||
*status));
|
||||
/* Cleanup from LAB-- reset and enable ESO.
|
||||
* This resets the PCF8584; since we've lost the bus, no
|
||||
* further attempts should be made by callers to clean up
|
||||
* (no i2c_stop() etc.)
|
||||
*/
|
||||
set_pcf(adap, 1, I2C_PCF_PIN);
|
||||
set_pcf(adap, 1, I2C_PCF_ESO);
|
||||
/* TODO: we should pause for a time period sufficient for any
|
||||
* running I2C transaction to complete-- the arbitration
|
||||
* logic won't work properly until the next START is seen.
|
||||
*/
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
|
||||
get_pcf(adap,1)));
|
||||
handle_lab(adap, status);
|
||||
return(-EINTR);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
menu "I2C Hardware Bus support"
|
||||
|
||||
comment "PC SMBus host controller drivers"
|
||||
depends on PCI
|
||||
|
||||
config I2C_ALI1535
|
||||
tristate "ALI 1535"
|
||||
depends on PCI
|
||||
|
@ -73,6 +76,186 @@ config I2C_AMD8111
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-amd8111.
|
||||
|
||||
config I2C_I801
|
||||
tristate "Intel 82801 (ICH)"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
801 family of mainboard I2C interfaces. Specifically, the following
|
||||
versions of the chipset are supported:
|
||||
82801AA
|
||||
82801AB
|
||||
82801BA
|
||||
82801CA/CAM
|
||||
82801DB
|
||||
82801EB/ER (ICH5/ICH5R)
|
||||
6300ESB
|
||||
ICH6
|
||||
ICH7
|
||||
ESB2
|
||||
ICH8
|
||||
ICH9
|
||||
Tolapai
|
||||
ICH10
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
||||
config I2C_ISCH
|
||||
tristate "Intel SCH SMBus 1.0"
|
||||
depends on PCI
|
||||
help
|
||||
Say Y here if you want to use SMBus controller on the Intel SCH
|
||||
based systems.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-isch.
|
||||
|
||||
config I2C_PIIX4
|
||||
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
PIIX4 family of mainboard I2C interfaces. Specifically, the following
|
||||
versions of the chipset are supported (note that Serverworks is part
|
||||
of Broadcom):
|
||||
Intel PIIX4
|
||||
Intel 440MX
|
||||
ATI IXP200
|
||||
ATI IXP300
|
||||
ATI IXP400
|
||||
ATI SB600
|
||||
ATI SB700
|
||||
ATI SB800
|
||||
Serverworks OSB4
|
||||
Serverworks CSB5
|
||||
Serverworks CSB6
|
||||
Serverworks HT-1000
|
||||
SMSC Victory66
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-piix4.
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Nvidia
|
||||
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-nforce2.
|
||||
|
||||
config I2C_NFORCE2_S4985
|
||||
tristate "SMBus multiplexing on the Tyan S4985"
|
||||
depends on I2C_NFORCE2 && EXPERIMENTAL
|
||||
help
|
||||
Enabling this option will add specific SMBus support for the Tyan
|
||||
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
||||
over 4 different channels, where the various memory module EEPROMs
|
||||
live. Saying yes here will give you access to these in addition
|
||||
to the trunk.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-nforce2-s4985.
|
||||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis5595.
|
||||
|
||||
config I2C_SIS630
|
||||
tristate "SiS 630/730"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630 and SiS730 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis630.
|
||||
|
||||
config I2C_SIS96X
|
||||
tristate "SiS 96x"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SiS
|
||||
96x SMBus (a subset of I2C) interfaces. Specifically, the following
|
||||
chipsets are supported:
|
||||
645/961
|
||||
645DX/961
|
||||
645DX/962
|
||||
648/961
|
||||
650/961
|
||||
735
|
||||
745
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis96x.
|
||||
|
||||
config I2C_VIA
|
||||
tristate "VIA VT82C586B"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C586B I2C interface
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-via.
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA VT82C596/82C686/82xx and CX700"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
VT82C596 and later SMBus interface. Specifically, the following
|
||||
chipsets are supported:
|
||||
VT82C596A/B
|
||||
VT82C686A/B
|
||||
VT8231
|
||||
VT8233/A
|
||||
VT8235
|
||||
VT8237R/A/S
|
||||
VT8251
|
||||
CX700
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-viapro.
|
||||
|
||||
comment "Mac SMBus host controller drivers"
|
||||
depends on PPC_CHRP || PPC_PMAC
|
||||
|
||||
config I2C_HYDRA
|
||||
tristate "CHRP Apple Hydra Mac I/O I2C interface"
|
||||
depends on PCI && PPC_CHRP && EXPERIMENTAL
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
This supports the use of the I2C interface in the Apple Hydra Mac
|
||||
I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
|
||||
have such a machine.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-hydra.
|
||||
|
||||
config I2C_POWERMAC
|
||||
tristate "Powermac I2C interface"
|
||||
depends on PPC_PMAC
|
||||
default y
|
||||
help
|
||||
This exposes the various PowerMac i2c interfaces to the linux i2c
|
||||
layer and to userland. It is used by various drivers on the PowerMac
|
||||
platform, and should generally be enabled.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-powermac.
|
||||
|
||||
comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
||||
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
|
||||
|
@ -101,10 +284,9 @@ config I2C_AU1550
|
|||
config I2C_BLACKFIN_TWI
|
||||
tristate "Blackfin TWI I2C support"
|
||||
depends on BLACKFIN
|
||||
depends on !BF561 && !BF531 && !BF532 && !BF533
|
||||
help
|
||||
This is the TWI I2C device driver for Blackfin BF522, BF525,
|
||||
BF527, BF534, BF536, BF537 and BF54x. For other Blackfin processors,
|
||||
please don't use this driver.
|
||||
This is the I2C bus driver for Blackfin on-chip TWI interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-bfin-twi.
|
||||
|
@ -117,6 +299,16 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
|
|||
help
|
||||
The unit of the TWI clock is kHz.
|
||||
|
||||
config I2C_CPM
|
||||
tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
|
||||
depends on (CPM1 || CPM2) && OF_I2C
|
||||
help
|
||||
This supports the use of the I2C interface on Freescale
|
||||
processors with CPM1 or CPM2.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-cpm.
|
||||
|
||||
config I2C_DAVINCI
|
||||
tristate "DaVinci I2C driver"
|
||||
depends on ARCH_DAVINCI
|
||||
|
@ -130,17 +322,6 @@ config I2C_DAVINCI
|
|||
devices such as DaVinci NIC.
|
||||
For details please see http://www.ti.com/davinci
|
||||
|
||||
config I2C_ELEKTOR
|
||||
tristate "Elektor ISA card"
|
||||
depends on ISA && BROKEN_ON_SMP
|
||||
select I2C_ALGOPCF
|
||||
help
|
||||
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
|
||||
such an adapter.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-elektor.
|
||||
|
||||
config I2C_GPIO
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
depends on GENERIC_GPIO
|
||||
|
@ -149,104 +330,6 @@ config I2C_GPIO
|
|||
This is a very simple bitbanging I2C driver utilizing the
|
||||
arch-neutral GPIO API to control the SCL and SDA lines.
|
||||
|
||||
config I2C_HYDRA
|
||||
tristate "CHRP Apple Hydra Mac I/O I2C interface"
|
||||
depends on PCI && PPC_CHRP && EXPERIMENTAL
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
This supports the use of the I2C interface in the Apple Hydra Mac
|
||||
I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
|
||||
have such a machine.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-hydra.
|
||||
|
||||
config I2C_I801
|
||||
tristate "Intel 82801 (ICH)"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
801 family of mainboard I2C interfaces. Specifically, the following
|
||||
versions of the chipset are supported:
|
||||
82801AA
|
||||
82801AB
|
||||
82801BA
|
||||
82801CA/CAM
|
||||
82801DB
|
||||
82801EB/ER (ICH5/ICH5R)
|
||||
6300ESB
|
||||
ICH6
|
||||
ICH7
|
||||
ESB2
|
||||
ICH8
|
||||
ICH9
|
||||
Tolapai
|
||||
ICH10
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
||||
config I2C_I810
|
||||
tristate "Intel 810/815 (DEPRECATED)"
|
||||
default n
|
||||
depends on PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
810/815 family of mainboard I2C interfaces. Specifically, the
|
||||
following versions of the chipset are supported:
|
||||
i810AA
|
||||
i810AB
|
||||
i810E
|
||||
i815
|
||||
i845G
|
||||
|
||||
This driver is deprecated in favor of the i810fb and intelfb drivers.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i810.
|
||||
|
||||
config I2C_PXA
|
||||
tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && ARCH_PXA
|
||||
help
|
||||
If you have devices in the PXA I2C bus, say yes to this option.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pxa.
|
||||
|
||||
config I2C_PXA_SLAVE
|
||||
bool "Intel PXA2XX I2C Slave comms support"
|
||||
depends on I2C_PXA
|
||||
help
|
||||
Support I2C slave mode communications on the PXA I2C bus. This
|
||||
is necessary for systems where the PXA may be a target on the
|
||||
I2C bus.
|
||||
|
||||
config I2C_PIIX4
|
||||
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
PIIX4 family of mainboard I2C interfaces. Specifically, the following
|
||||
versions of the chipset are supported (note that Serverworks is part
|
||||
of Broadcom):
|
||||
Intel PIIX4
|
||||
Intel 440MX
|
||||
ATI IXP200
|
||||
ATI IXP300
|
||||
ATI IXP400
|
||||
ATI SB600
|
||||
ATI SB700
|
||||
ATI SB800
|
||||
Serverworks OSB4
|
||||
Serverworks CSB5
|
||||
Serverworks CSB6
|
||||
Serverworks HT-1000
|
||||
SMSC Victory66
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-piix4.
|
||||
|
||||
config I2C_IBM_IIC
|
||||
tristate "IBM PPC 4xx on-chip I2C interface"
|
||||
depends on 4xx
|
||||
|
@ -281,18 +364,6 @@ config I2C_IXP2000
|
|||
This driver is deprecated and will be dropped soon. Use i2c-gpio
|
||||
instead.
|
||||
|
||||
config I2C_POWERMAC
|
||||
tristate "Powermac I2C interface"
|
||||
depends on PPC_PMAC
|
||||
default y
|
||||
help
|
||||
This exposes the various PowerMac i2c interfaces to the linux i2c
|
||||
layer and to userland. It is used by various drivers on the PowerMac
|
||||
platform, and should generally be enabled.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-powermac.
|
||||
|
||||
config I2C_MPC
|
||||
tristate "MPC107/824x/85xx/52xx/86xx"
|
||||
depends on PPC32
|
||||
|
@ -305,15 +376,15 @@ config I2C_MPC
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mpc.
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on PCI
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
help
|
||||
If you say yes to this option, support will be included for the Nvidia
|
||||
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-nforce2.
|
||||
will be called i2c-mv64xxx.
|
||||
|
||||
config I2C_OCORES
|
||||
tristate "OpenCores I2C Controller"
|
||||
|
@ -336,6 +407,89 @@ config I2C_OMAP
|
|||
Like OMAP1510/1610/1710/5912 and OMAP242x.
|
||||
For details see http://www.ti.com/omap.
|
||||
|
||||
config I2C_PASEMI
|
||||
tristate "PA Semi SMBus interface"
|
||||
depends on PPC_PASEMI && PCI
|
||||
help
|
||||
Supports the PA Semi PWRficient on-chip SMBus interfaces.
|
||||
|
||||
config I2C_PNX
|
||||
tristate "I2C bus support for Philips PNX targets"
|
||||
depends on ARCH_PNX4008
|
||||
help
|
||||
This driver supports the Philips IP3204 I2C IP block master and/or
|
||||
slave controller
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pnx.
|
||||
|
||||
config I2C_PXA
|
||||
tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && ARCH_PXA
|
||||
help
|
||||
If you have devices in the PXA I2C bus, say yes to this option.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pxa.
|
||||
|
||||
config I2C_PXA_SLAVE
|
||||
bool "Intel PXA2XX I2C Slave comms support"
|
||||
depends on I2C_PXA
|
||||
help
|
||||
Support I2C slave mode communications on the PXA I2C bus. This
|
||||
is necessary for systems where the PXA may be a target on the
|
||||
I2C bus.
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on ARCH_S3C2410
|
||||
help
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung S3C2410 based System-on-Chip devices.
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
depends on CPU_SUBTYPE_SH7760
|
||||
help
|
||||
This driver supports the 2 I2C interfaces on the Renesas SH7760.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh7760.
|
||||
|
||||
config I2C_SH_MOBILE
|
||||
tristate "SuperH Mobile I2C Controller"
|
||||
depends on SUPERH
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Renesas SH-Mobile processor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh_mobile.
|
||||
|
||||
config I2C_SIMTEC
|
||||
tristate "Simtec Generic I2C interface"
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for
|
||||
the Simtec Generic I2C interface. This driver is for the
|
||||
simple I2C bus used on newer Simtec products for general
|
||||
I2C, such as DDC on the Simtec BBD2016A.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-simtec.
|
||||
|
||||
config I2C_VERSATILE
|
||||
tristate "ARM Versatile/Realview I2C bus support"
|
||||
depends on ARCH_VERSATILE || ARCH_REALVIEW
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say yes if you want to support the I2C serial bus on ARMs Versatile
|
||||
range of platforms.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-versatile.
|
||||
|
||||
comment "External I2C/SMBus adapter drivers"
|
||||
|
||||
config I2C_PARPORT
|
||||
tristate "Parallel port adapter"
|
||||
depends on PARPORT
|
||||
|
@ -383,50 +537,106 @@ config I2C_PARPORT_LIGHT
|
|||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport-light.
|
||||
|
||||
config I2C_PASEMI
|
||||
tristate "PA Semi SMBus interface"
|
||||
depends on PPC_PASEMI && PCI
|
||||
help
|
||||
Supports the PA Semi PWRficient on-chip SMBus interfaces.
|
||||
|
||||
config I2C_PROSAVAGE
|
||||
tristate "S3/VIA (Pro)Savage (DEPRECATED)"
|
||||
config I2C_TAOS_EVM
|
||||
tristate "TAOS evaluation module"
|
||||
depends on EXPERIMENTAL
|
||||
select SERIO
|
||||
select SERIO_SERPORT
|
||||
default n
|
||||
depends on PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C bus and DDC bus of the S3VIA embedded Savage4 and ProSavage8
|
||||
graphics processors.
|
||||
chipsets supported:
|
||||
S3/VIA KM266/VT8375 aka ProSavage8
|
||||
S3/VIA KM133/VT8365 aka Savage4
|
||||
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.
|
||||
|
||||
This driver is deprecated in favor of the savagefb driver.
|
||||
If unsure, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-prosavage.
|
||||
will be called i2c-taos-evm.
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on ARCH_S3C2410
|
||||
config I2C_TINY_USB
|
||||
tristate "Tiny-USB adapter"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung S3C2410 based System-on-Chip devices.
|
||||
If you say yes to this option, support will be included for the
|
||||
i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
|
||||
http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
|
||||
|
||||
config I2C_SAVAGE4
|
||||
tristate "S3 Savage 4 (DEPRECATED)"
|
||||
default n
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-tiny-usb.
|
||||
|
||||
comment "Graphics adapter I2C/DDC channel drivers"
|
||||
depends on PCI
|
||||
|
||||
config I2C_VOODOO3
|
||||
tristate "Voodoo 3"
|
||||
depends on PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
S3 Savage 4 I2C interface.
|
||||
|
||||
This driver is deprecated in favor of the savagefb driver.
|
||||
Voodoo 3 I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-savage4.
|
||||
will be called i2c-voodoo3.
|
||||
|
||||
comment "Other I2C/SMBus bus drivers"
|
||||
|
||||
config I2C_ACORN
|
||||
tristate "Acorn IOC/IOMD I2C bus support"
|
||||
depends on ARCH_ACORN
|
||||
default y
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say yes if you want to support the I2C bus on Acorn platforms.
|
||||
|
||||
If you don't know, say Y.
|
||||
|
||||
config I2C_ELEKTOR
|
||||
tristate "Elektor ISA card"
|
||||
depends on ISA && BROKEN_ON_SMP
|
||||
select I2C_ALGOPCF
|
||||
help
|
||||
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
|
||||
such an adapter.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-elektor.
|
||||
|
||||
config I2C_PCA_ISA
|
||||
tristate "PCA9564 on an ISA bus"
|
||||
depends on ISA
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports ISA boards using the Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-isa.
|
||||
|
||||
This device is almost undetectable and using this driver on a
|
||||
system which doesn't have this device will result in long
|
||||
delays when I2C/SMBus chip drivers are loaded (e.g. at boot
|
||||
time). If unsure, say N.
|
||||
|
||||
config I2C_PCA_PLATFORM
|
||||
tristate "PCA9564 as platform device"
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports a memory mapped Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-platform.
|
||||
|
||||
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.
|
||||
|
||||
config I2C_SIBYTE
|
||||
tristate "SiByte SMBus interface"
|
||||
|
@ -434,17 +644,18 @@ config I2C_SIBYTE
|
|||
help
|
||||
Supports the SiByte SOC on-chip I2C interfaces (2 channels).
|
||||
|
||||
config I2C_SIMTEC
|
||||
tristate "Simtec Generic I2C interface"
|
||||
select I2C_ALGOBIT
|
||||
config I2C_STUB
|
||||
tristate "I2C/SMBus Test Stub"
|
||||
depends on EXPERIMENTAL && m
|
||||
default 'n'
|
||||
help
|
||||
If you say yes to this option, support will be included for
|
||||
the Simtec Generic I2C interface. This driver is for the
|
||||
simple I2C bus used on newer Simtec products for general
|
||||
I2C, such as DDC on the Simtec BBD2016A.
|
||||
This module may be useful to developers of SMBus client drivers,
|
||||
especially for certain kinds of sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-simtec.
|
||||
If you do build this module, be sure to read the notes and warnings
|
||||
in <file:Documentation/i2c/i2c-stub>.
|
||||
|
||||
If you don't know what to do here, definitely say N.
|
||||
|
||||
config SCx200_I2C
|
||||
tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
|
||||
|
@ -489,220 +700,4 @@ config SCx200_ACB
|
|||
This support is also available as a module. If so, the module
|
||||
will be called scx200_acb.
|
||||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis5595.
|
||||
|
||||
config I2C_SIS630
|
||||
tristate "SiS 630/730"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630 and SiS730 SMBus (a subset of I2C) interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis630.
|
||||
|
||||
config I2C_SIS96X
|
||||
tristate "SiS 96x"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SiS
|
||||
96x SMBus (a subset of I2C) interfaces. Specifically, the following
|
||||
chipsets are supported:
|
||||
645/961
|
||||
645DX/961
|
||||
645DX/962
|
||||
648/961
|
||||
650/961
|
||||
735
|
||||
745
|
||||
|
||||
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
|
||||
default 'n'
|
||||
help
|
||||
This module may be useful to developers of SMBus client drivers,
|
||||
especially for certain kinds of sensor chips.
|
||||
|
||||
If you do build this module, be sure to read the notes and warnings
|
||||
in <file:Documentation/i2c/i2c-stub>.
|
||||
|
||||
If you don't know what to do here, definitely say N.
|
||||
|
||||
config I2C_TINY_USB
|
||||
tristate "I2C-Tiny-USB"
|
||||
depends on USB
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
|
||||
http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-tiny-usb.
|
||||
|
||||
config I2C_VERSATILE
|
||||
tristate "ARM Versatile/Realview I2C bus support"
|
||||
depends on ARCH_VERSATILE || ARCH_REALVIEW
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say yes if you want to support the I2C serial bus on ARMs Versatile
|
||||
range of platforms.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-versatile.
|
||||
|
||||
config I2C_ACORN
|
||||
tristate "Acorn IOC/IOMD I2C bus support"
|
||||
depends on ARCH_ACORN
|
||||
default y
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say yes if you want to support the I2C bus on Acorn platforms.
|
||||
|
||||
If you don't know, say Y.
|
||||
|
||||
config I2C_VIA
|
||||
tristate "VIA 82C586B"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C586B I2C interface
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-via.
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA VT82C596/82C686/82xx and CX700"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
VT82C596 and later SMBus interface. Specifically, the following
|
||||
chipsets are supported:
|
||||
VT82C596A/B
|
||||
VT82C686A/B
|
||||
VT8231
|
||||
VT8233/A
|
||||
VT8235
|
||||
VT8237R/A/S
|
||||
VT8251
|
||||
CX700
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-viapro.
|
||||
|
||||
config I2C_VOODOO3
|
||||
tristate "Voodoo 3"
|
||||
depends on PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Voodoo 3 I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-voodoo3.
|
||||
|
||||
config I2C_PCA_ISA
|
||||
tristate "PCA9564 on an ISA bus"
|
||||
depends on ISA
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports ISA boards using the Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-isa.
|
||||
|
||||
This device is almost undetectable and using this driver on a
|
||||
system which doesn't have this device will result in long
|
||||
delays when I2C/SMBus chip drivers are loaded (e.g. at boot
|
||||
time). If unsure, say N.
|
||||
|
||||
config I2C_PCA_PLATFORM
|
||||
tristate "PCA9564 as platform device"
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports a memory mapped Philips PCA9564
|
||||
parallel bus to I2C bus controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pca-platform.
|
||||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mv64xxx.
|
||||
|
||||
config I2C_PNX
|
||||
tristate "I2C bus support for Philips PNX targets"
|
||||
depends on ARCH_PNX4008
|
||||
help
|
||||
This driver supports the Philips IP3204 I2C IP block master and/or
|
||||
slave controller
|
||||
|
||||
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.
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
depends on CPU_SUBTYPE_SH7760
|
||||
help
|
||||
This driver supports the 2 I2C interfaces on the Renesas SH7760.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh7760.
|
||||
|
||||
config I2C_SH_MOBILE
|
||||
tristate "SuperH Mobile I2C Controller"
|
||||
depends on SUPERH
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Renesas SH-Mobile processor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sh_mobile.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -2,57 +2,68 @@
|
|||
# Makefile for the i2c bus drivers.
|
||||
#
|
||||
|
||||
# PC SMBus host controller drivers
|
||||
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
|
||||
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
|
||||
obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
|
||||
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
|
||||
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
|
||||
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
|
||||
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
|
||||
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
|
||||
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
|
||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
|
||||
obj-$(CONFIG_I2C_I801) += i2c-i801.o
|
||||
obj-$(CONFIG_I2C_I810) += i2c-i810.o
|
||||
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
|
||||
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
|
||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
|
||||
obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
|
||||
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
|
||||
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
|
||||
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
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_PCA_PLATFORM) += i2c-pca-platform.o
|
||||
obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.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_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
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
|
||||
obj-$(CONFIG_I2C_VIA) += i2c-via.o
|
||||
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
|
||||
|
||||
# Mac SMBus host controller drivers
|
||||
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
|
||||
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
|
||||
|
||||
# Embebbed system I2C/SMBus host controller drivers
|
||||
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
|
||||
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
|
||||
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
|
||||
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
|
||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
|
||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
|
||||
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
|
||||
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
|
||||
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
|
||||
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
||||
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
|
||||
|
||||
# External I2C/SMBus adapter drivers
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
|
||||
|
||||
# Graphics adapter I2C/DDC channel drivers
|
||||
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
|
||||
|
||||
# Other I2C/SMBus bus drivers
|
||||
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
|
||||
obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
|
||||
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
i2c-ali1535.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
||||
|
@ -61,6 +59,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
|
@ -159,6 +158,11 @@ static int ali1535_setup(struct pci_dev *dev)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
|
||||
ali1535_driver.name);
|
||||
if (retval)
|
||||
goto exit;
|
||||
|
||||
if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
|
||||
ali1535_driver.name)) {
|
||||
dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n",
|
||||
|
@ -259,7 +263,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
|||
dev_err(&adap->dev,
|
||||
"SMBus reset failed! (0x%02x) - controller or "
|
||||
"device on bus is probably hung\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
}
|
||||
} else {
|
||||
/* check and clear done bit */
|
||||
|
@ -281,12 +285,12 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
|||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "SMBus Timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & ALI1535_STS_FAIL) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
|
@ -295,7 +299,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
|||
* do a printk. This means that bus collisions go unreported.
|
||||
*/
|
||||
if (temp & ALI1535_STS_BUSERR) {
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
dev_dbg(&adap->dev,
|
||||
"Error: no response or bus collision ADD=%02x\n",
|
||||
inb_p(SMBHSTADD));
|
||||
|
@ -303,13 +307,13 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
|||
|
||||
/* haven't ever seen this */
|
||||
if (temp & ALI1535_STS_DEV) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_err(&adap->dev, "Error: device error\n");
|
||||
}
|
||||
|
||||
/* check to see if the "command complete" indication is set */
|
||||
if (!(temp & ALI1535_STS_DONE)) {
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "Error: command never completed\n");
|
||||
}
|
||||
|
||||
|
@ -332,7 +336,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write, u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
|
@ -357,10 +361,6 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
|
|||
outb_p(0xFF, SMBHSTSTS);
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
|
||||
result = -1;
|
||||
goto EXIT;
|
||||
case I2C_SMBUS_QUICK:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
SMBHSTADD);
|
||||
|
@ -418,14 +418,16 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
|
|||
outb_p(data->block[i], SMBBLKDAT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ali1535_transaction(adap)) {
|
||||
/* Error in transaction */
|
||||
result = -1;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
result = -EOPNOTSUPP;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
result = ali1535_transaction(adap);
|
||||
if (result)
|
||||
goto EXIT;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) {
|
||||
result = 0;
|
||||
goto EXIT;
|
||||
|
@ -475,7 +477,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter ali1535_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_ALI1535,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define ALI1563_MAX_TIMEOUT 500
|
||||
#define ALI1563_SMBBA 0x80
|
||||
|
@ -67,6 +68,7 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
|
|||
{
|
||||
u32 data;
|
||||
int timeout;
|
||||
int status = -EIO;
|
||||
|
||||
dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, "
|
||||
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
|
||||
|
@ -103,13 +105,15 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
|
|||
/* Issue 'kill' to host controller */
|
||||
outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
|
||||
data = inb_p(SMB_HST_STS);
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* device error - no response, ignore the autodetection case */
|
||||
if ((data & HST_STS_DEVERR) && (size != HST_CNTL2_QUICK)) {
|
||||
dev_err(&a->dev, "Device error!\n");
|
||||
if (data & HST_STS_DEVERR) {
|
||||
if (size != HST_CNTL2_QUICK)
|
||||
dev_err(&a->dev, "Device error!\n");
|
||||
status = -ENXIO;
|
||||
}
|
||||
|
||||
/* bus collision */
|
||||
if (data & HST_STS_BUSERR) {
|
||||
dev_err(&a->dev, "Bus collision!\n");
|
||||
|
@ -122,13 +126,14 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
|
|||
outb_p(0x0,SMB_HST_CNTL2);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ali1563_block_start(struct i2c_adapter * a)
|
||||
{
|
||||
u32 data;
|
||||
int timeout;
|
||||
int status = -EIO;
|
||||
|
||||
dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, "
|
||||
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
|
||||
|
@ -164,13 +169,20 @@ static int ali1563_block_start(struct i2c_adapter * a)
|
|||
|
||||
if (timeout && !(data & HST_STS_BAD))
|
||||
return 0;
|
||||
|
||||
if (timeout == 0)
|
||||
status = -ETIMEDOUT;
|
||||
|
||||
if (data & HST_STS_DEVERR)
|
||||
status = -ENXIO;
|
||||
|
||||
dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
|
||||
timeout ? "Timeout " : "",
|
||||
timeout ? "" : "Timeout ",
|
||||
data & HST_STS_FAIL ? "Transaction Failed " : "",
|
||||
data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
|
||||
data & HST_STS_DEVERR ? "Device Error " : "",
|
||||
!(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
|
||||
return -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw)
|
||||
|
@ -235,10 +247,6 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
|
|||
|
||||
/* Map the size to what the chip understands */
|
||||
switch (size) {
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
dev_err(&a->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
|
||||
error = -EINVAL;
|
||||
break;
|
||||
case I2C_SMBUS_QUICK:
|
||||
size = HST_CNTL2_QUICK;
|
||||
break;
|
||||
|
@ -254,6 +262,10 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
|
|||
case I2C_SMBUS_BLOCK_DATA:
|
||||
size = HST_CNTL2_BLOCK;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&a->dev, "Unsupported transaction %d\n", size);
|
||||
error = -EOPNOTSUPP;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
|
||||
|
@ -345,6 +357,10 @@ static int __devinit ali1563_setup(struct pci_dev * dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (acpi_check_region(ali1563_smba, ALI1563_SMB_IOSIZE,
|
||||
ali1563_pci_driver.name))
|
||||
goto Err;
|
||||
|
||||
if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE,
|
||||
ali1563_pci_driver.name)) {
|
||||
dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n",
|
||||
|
@ -371,7 +387,7 @@ static const struct i2c_algorithm ali1563_algorithm = {
|
|||
static struct i2c_adapter ali1563_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_ALI1563,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &ali1563_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com> and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
@ -68,6 +66,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* ALI15X3 SMBus address offsets */
|
||||
|
@ -166,6 +165,10 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
|
|||
if(force_addr)
|
||||
ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
|
||||
|
||||
if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
|
||||
ali15x3_driver.name))
|
||||
return -EBUSY;
|
||||
|
||||
if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
|
||||
ali15x3_driver.name)) {
|
||||
dev_err(&ALI15X3_dev->dev,
|
||||
|
@ -282,7 +285,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
|||
dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
|
||||
"controller or device on bus is probably hung\n",
|
||||
temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
}
|
||||
} else {
|
||||
/* check and clear done bit */
|
||||
|
@ -304,12 +307,12 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
|||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&adap->dev, "SMBus Timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & ALI15X3_STS_TERM) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
|
@ -320,7 +323,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
|||
This means that bus collisions go unreported.
|
||||
*/
|
||||
if (temp & ALI15X3_STS_COLL) {
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
dev_dbg(&adap->dev,
|
||||
"Error: no response or bus collision ADD=%02x\n",
|
||||
inb_p(SMBHSTADD));
|
||||
|
@ -328,7 +331,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
|||
|
||||
/* haven't ever seen this */
|
||||
if (temp & ALI15X3_STS_DEV) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_err(&adap->dev, "Error: device error\n");
|
||||
}
|
||||
dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
|
||||
|
@ -338,7 +341,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write, u8 command,
|
||||
int size, union i2c_smbus_data * data)
|
||||
|
@ -362,9 +365,6 @@ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
|
|||
}
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
|
||||
return -1;
|
||||
case I2C_SMBUS_QUICK:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
SMBHSTADD);
|
||||
|
@ -417,12 +417,16 @@ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
|
|||
}
|
||||
size = ALI15X3_BLOCK_DATA;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
outb_p(size, SMBHSTCNT); /* output command */
|
||||
|
||||
if (ali15x3_transaction(adap)) /* Error in transaction */
|
||||
return -1;
|
||||
temp = ali15x3_transaction(adap);
|
||||
if (temp)
|
||||
return temp;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
|
||||
return 0;
|
||||
|
@ -470,7 +474,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter ali15x3_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_ALI15X3,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
|
|||
/* We exclude the multiplexed addresses */
|
||||
if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
|
||||
|| addr == 0x18)
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
|
||||
mutex_lock(&amd756_lock);
|
||||
|
||||
|
@ -86,7 +86,7 @@ static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
|
|||
|
||||
/* We exclude the non-multiplexed addresses */
|
||||
if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
|
||||
mutex_lock(&amd756_lock);
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
amd756.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
|
||||
|
||||
Shamelessly ripped from i2c-piix4.c:
|
||||
|
@ -45,6 +42,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* AMD756 SMBus address offsets */
|
||||
|
@ -151,17 +149,17 @@ static int amd756_transaction(struct i2c_adapter *adap)
|
|||
}
|
||||
|
||||
if (temp & GS_PRERR_STS) {
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
|
||||
}
|
||||
|
||||
if (temp & GS_COL_STS) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_warn(&adap->dev, "SMBus collision!\n");
|
||||
}
|
||||
|
||||
if (temp & GS_TO_STS) {
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
|
||||
}
|
||||
|
||||
|
@ -189,22 +187,18 @@ static int amd756_transaction(struct i2c_adapter *adap)
|
|||
outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
|
||||
msleep(100);
|
||||
outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
int i, len;
|
||||
int status;
|
||||
|
||||
/** TODO: Should I supporte the 10-bit transfers? */
|
||||
switch (size) {
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
dev_dbg(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
|
||||
/* TODO: Well... It is supported, I'm just not sure what to do here... */
|
||||
return -1;
|
||||
case I2C_SMBUS_QUICK:
|
||||
outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
SMB_HOST_ADDRESS);
|
||||
|
@ -251,13 +245,17 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
|
|||
}
|
||||
size = AMD756_BLOCK_DATA;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* How about enabling interrupts... */
|
||||
outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
|
||||
|
||||
if (amd756_transaction(adap)) /* Error in transaction */
|
||||
return -1;
|
||||
status = amd756_transaction(adap);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
|
||||
return 0;
|
||||
|
@ -301,7 +299,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
struct i2c_adapter amd756_smbus = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_AMD756,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
@ -368,6 +366,11 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
|
|||
amd756_ioport += SMB_ADDR_OFFSET;
|
||||
}
|
||||
|
||||
error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
|
||||
amd756_driver.name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
|
||||
dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
|
||||
amd756_ioport);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -77,7 +78,7 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
|
|||
if (!timeout) {
|
||||
dev_warn(&smbus->dev->dev,
|
||||
"Timeout while waiting for IBF to clear\n");
|
||||
return -1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -93,7 +94,7 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
|
|||
if (!timeout) {
|
||||
dev_warn(&smbus->dev->dev,
|
||||
"Timeout while waiting for OBF to set\n");
|
||||
return -1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -102,16 +103,21 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
|
|||
static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
|
||||
unsigned char *data)
|
||||
{
|
||||
if (amd_ec_wait_write(smbus))
|
||||
return -1;
|
||||
int status;
|
||||
|
||||
status = amd_ec_wait_write(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
|
||||
|
||||
if (amd_ec_wait_write(smbus))
|
||||
return -1;
|
||||
status = amd_ec_wait_write(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
outb(address, smbus->base + AMD_EC_DATA);
|
||||
|
||||
if (amd_ec_wait_read(smbus))
|
||||
return -1;
|
||||
status = amd_ec_wait_read(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
*data = inb(smbus->base + AMD_EC_DATA);
|
||||
|
||||
return 0;
|
||||
|
@ -120,16 +126,21 @@ static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
|
|||
static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
|
||||
unsigned char data)
|
||||
{
|
||||
if (amd_ec_wait_write(smbus))
|
||||
return -1;
|
||||
int status;
|
||||
|
||||
status = amd_ec_wait_write(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
|
||||
|
||||
if (amd_ec_wait_write(smbus))
|
||||
return -1;
|
||||
status = amd_ec_wait_write(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
outb(address, smbus->base + AMD_EC_DATA);
|
||||
|
||||
if (amd_ec_wait_write(smbus))
|
||||
return -1;
|
||||
status = amd_ec_wait_write(smbus);
|
||||
if (status)
|
||||
return status;
|
||||
outb(data, smbus->base + AMD_EC_DATA);
|
||||
|
||||
return 0;
|
||||
|
@ -267,12 +278,17 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
|
|||
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
|
||||
amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
|
||||
|
||||
/* FIXME this discards status from ec_read(); so temp[0] will
|
||||
* hold stack garbage ... the rest of this routine will act
|
||||
* nonsensically. Ignored ec_write() status might explain
|
||||
* some such failures...
|
||||
*/
|
||||
amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
|
||||
|
||||
if (~temp[0] & AMD_SMB_STS_DONE) {
|
||||
|
@ -286,7 +302,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
|
|||
}
|
||||
|
||||
if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
return 0;
|
||||
|
@ -359,6 +375,10 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
|
|||
smbus->base = pci_resource_start(dev, 0);
|
||||
smbus->size = pci_resource_len(dev, 0);
|
||||
|
||||
error = acpi_check_resource_conflict(&dev->resource[0]);
|
||||
if (error)
|
||||
goto out_kfree;
|
||||
|
||||
if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
|
||||
error = -EBUSY;
|
||||
goto out_kfree;
|
||||
|
@ -368,7 +388,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
|
|||
snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
|
||||
"SMBus2 AMD8111 adapter at %04x", smbus->base);
|
||||
smbus->adapter.id = I2C_HW_SMBUS_AMD8111;
|
||||
smbus->adapter.class = I2C_CLASS_HWMON;
|
||||
smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
smbus->adapter.algo = &smbus_algorithm;
|
||||
smbus->adapter.algo_data = smbus;
|
||||
|
||||
|
|
|
@ -269,9 +269,13 @@ static int
|
|||
au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct i2c_au1550_data *adap = i2c_adap->algo_data;
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base;
|
||||
struct i2c_msg *p;
|
||||
int i, err = 0;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_ENABLE;
|
||||
au_sync();
|
||||
|
||||
for (i = 0; !err && i < num; i++) {
|
||||
p = &msgs[i];
|
||||
err = do_address(adap, p->addr, p->flags & I2C_M_RD,
|
||||
|
@ -288,6 +292,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
|
|||
*/
|
||||
if (err == 0)
|
||||
err = num;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_SUSPEND;
|
||||
au_sync();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -302,53 +310,11 @@ static const struct i2c_algorithm au1550_algo = {
|
|||
.functionality = au1550_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
* Prior to calling us, the 50MHz clock frequency and routing
|
||||
* must have been set up for the PSC indicated by the adapter.
|
||||
*/
|
||||
static int __devinit
|
||||
i2c_au1550_probe(struct platform_device *pdev)
|
||||
static void i2c_au1550_setup(struct i2c_au1550_data *priv)
|
||||
{
|
||||
struct i2c_au1550_data *priv;
|
||||
volatile psc_smb_t *sp;
|
||||
struct resource *r;
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
u32 stat;
|
||||
int ret;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
|
||||
pdev->name);
|
||||
if (!priv->ioarea) {
|
||||
ret = -EBUSY;
|
||||
goto out_mem;
|
||||
}
|
||||
|
||||
priv->psc_base = CKSEG1ADDR(r->start);
|
||||
priv->xfer_timeout = 200;
|
||||
priv->ack_timeout = 200;
|
||||
|
||||
priv->adap.id = I2C_HW_AU1550_PSC;
|
||||
priv->adap.nr = pdev->id;
|
||||
priv->adap.algo = &au1550_algo;
|
||||
priv->adap.algo_data = priv;
|
||||
priv->adap.dev.parent = &pdev->dev;
|
||||
strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
|
||||
|
||||
/* Now, set up the PSC for SMBus PIO mode.
|
||||
*/
|
||||
sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
|
||||
|
@ -384,7 +350,66 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
do {
|
||||
stat = sp->psc_smbstat;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBSTAT_DR) == 0);
|
||||
} while ((stat & PSC_SMBSTAT_SR) == 0);
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_SUSPEND;
|
||||
au_sync();
|
||||
}
|
||||
|
||||
static void i2c_au1550_disable(struct i2c_au1550_data *priv)
|
||||
{
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
|
||||
sp->psc_smbcfg = 0;
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
}
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
* Prior to calling us, the 50MHz clock frequency and routing
|
||||
* must have been set up for the PSC indicated by the adapter.
|
||||
*/
|
||||
static int __devinit
|
||||
i2c_au1550_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_au1550_data *priv;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
|
||||
pdev->name);
|
||||
if (!priv->ioarea) {
|
||||
ret = -EBUSY;
|
||||
goto out_mem;
|
||||
}
|
||||
|
||||
priv->psc_base = CKSEG1ADDR(r->start);
|
||||
priv->xfer_timeout = 200;
|
||||
priv->ack_timeout = 200;
|
||||
|
||||
priv->adap.id = I2C_HW_AU1550_PSC;
|
||||
priv->adap.nr = pdev->id;
|
||||
priv->adap.algo = &au1550_algo;
|
||||
priv->adap.algo_data = priv;
|
||||
priv->adap.dev.parent = &pdev->dev;
|
||||
strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
|
||||
|
||||
/* Now, set up the PSC for SMBus PIO mode.
|
||||
*/
|
||||
i2c_au1550_setup(priv);
|
||||
|
||||
ret = i2c_add_numbered_adapter(&priv->adap);
|
||||
if (ret == 0) {
|
||||
|
@ -392,10 +417,7 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* disable the PSC */
|
||||
sp->psc_smbcfg = 0;
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
i2c_au1550_disable(priv);
|
||||
|
||||
release_resource(priv->ioarea);
|
||||
kfree(priv->ioarea);
|
||||
|
@ -409,27 +431,24 @@ static int __devexit
|
|||
i2c_au1550_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
i2c_del_adapter(&priv->adap);
|
||||
sp->psc_smbcfg = 0;
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
i2c_au1550_disable(priv);
|
||||
release_resource(priv->ioarea);
|
||||
kfree(priv->ioarea);
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int
|
||||
i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_SUSPEND;
|
||||
au_sync();
|
||||
i2c_au1550_disable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -437,14 +456,15 @@ static int
|
|||
i2c_au1550_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_ENABLE;
|
||||
au_sync();
|
||||
while (!(sp->psc_smbstat & PSC_SMBSTAT_SR))
|
||||
au_sync();
|
||||
i2c_au1550_setup(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define i2c_au1550_suspend NULL
|
||||
#define i2c_au1550_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver au1xpsc_smbus_driver = {
|
||||
.driver = {
|
||||
|
|
745
drivers/i2c/busses/i2c-cpm.c
Normal file
745
drivers/i2c/busses/i2c-cpm.c
Normal file
|
@ -0,0 +1,745 @@
|
|||
/*
|
||||
* Freescale CPM1/CPM2 I2C interface.
|
||||
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
|
||||
*
|
||||
* moved into proper i2c interface;
|
||||
* Brad Parker (brad@heeltoe.com)
|
||||
*
|
||||
* Parts from dbox2_i2c.c (cvs.tuxbox.org)
|
||||
* (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net)
|
||||
*
|
||||
* (C) 2007 Montavista Software, Inc.
|
||||
* Vitaly Bordug <vitb@kernel.crashing.org>
|
||||
*
|
||||
* Converted to of_platform_device. Renamed to i2c-cpm.c.
|
||||
* (C) 2007,2008 Jochen Friedrich <jochen@scram.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
#include <asm/cpm.h>
|
||||
|
||||
/* Try to define this if you have an older CPU (earlier than rev D4) */
|
||||
/* However, better use a GPIO based bitbang driver in this case :/ */
|
||||
#undef I2C_CHIP_ERRATA
|
||||
|
||||
#define CPM_MAX_READ 513
|
||||
#define CPM_MAXBD 4
|
||||
|
||||
#define I2C_EB (0x10) /* Big endian mode */
|
||||
#define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */
|
||||
|
||||
#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
|
||||
|
||||
/* I2C parameter RAM. */
|
||||
struct i2c_ram {
|
||||
ushort rbase; /* Rx Buffer descriptor base address */
|
||||
ushort tbase; /* Tx Buffer descriptor base address */
|
||||
u_char rfcr; /* Rx function code */
|
||||
u_char tfcr; /* Tx function code */
|
||||
ushort mrblr; /* Max receive buffer length */
|
||||
uint rstate; /* Internal */
|
||||
uint rdp; /* Internal */
|
||||
ushort rbptr; /* Rx Buffer descriptor pointer */
|
||||
ushort rbc; /* Internal */
|
||||
uint rxtmp; /* Internal */
|
||||
uint tstate; /* Internal */
|
||||
uint tdp; /* Internal */
|
||||
ushort tbptr; /* Tx Buffer descriptor pointer */
|
||||
ushort tbc; /* Internal */
|
||||
uint txtmp; /* Internal */
|
||||
char res1[4]; /* Reserved */
|
||||
ushort rpbase; /* Relocation pointer */
|
||||
char res2[2]; /* Reserved */
|
||||
};
|
||||
|
||||
#define I2COM_START 0x80
|
||||
#define I2COM_MASTER 0x01
|
||||
#define I2CER_TXE 0x10
|
||||
#define I2CER_BUSY 0x04
|
||||
#define I2CER_TXB 0x02
|
||||
#define I2CER_RXB 0x01
|
||||
#define I2MOD_EN 0x01
|
||||
|
||||
/* I2C Registers */
|
||||
struct i2c_reg {
|
||||
u8 i2mod;
|
||||
u8 res1[3];
|
||||
u8 i2add;
|
||||
u8 res2[3];
|
||||
u8 i2brg;
|
||||
u8 res3[3];
|
||||
u8 i2com;
|
||||
u8 res4[3];
|
||||
u8 i2cer;
|
||||
u8 res5[3];
|
||||
u8 i2cmr;
|
||||
};
|
||||
|
||||
struct cpm_i2c {
|
||||
char *base;
|
||||
struct of_device *ofdev;
|
||||
struct i2c_adapter adap;
|
||||
uint dp_addr;
|
||||
int version; /* CPM1=1, CPM2=2 */
|
||||
int irq;
|
||||
int cp_command;
|
||||
int freq;
|
||||
struct i2c_reg __iomem *i2c_reg;
|
||||
struct i2c_ram __iomem *i2c_ram;
|
||||
u16 i2c_addr;
|
||||
wait_queue_head_t i2c_wait;
|
||||
cbd_t __iomem *tbase;
|
||||
cbd_t __iomem *rbase;
|
||||
u_char *txbuf[CPM_MAXBD];
|
||||
u_char *rxbuf[CPM_MAXBD];
|
||||
u32 txdma[CPM_MAXBD];
|
||||
u32 rxdma[CPM_MAXBD];
|
||||
};
|
||||
|
||||
static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct cpm_i2c *cpm;
|
||||
struct i2c_reg __iomem *i2c_reg;
|
||||
struct i2c_adapter *adap = dev_id;
|
||||
int i;
|
||||
|
||||
cpm = i2c_get_adapdata(dev_id);
|
||||
i2c_reg = cpm->i2c_reg;
|
||||
|
||||
/* Clear interrupt. */
|
||||
i = in_8(&i2c_reg->i2cer);
|
||||
out_8(&i2c_reg->i2cer, i);
|
||||
|
||||
dev_dbg(&adap->dev, "Interrupt: %x\n", i);
|
||||
|
||||
wake_up_interruptible(&cpm->i2c_wait);
|
||||
|
||||
return i ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static void cpm_reset_i2c_params(struct cpm_i2c *cpm)
|
||||
{
|
||||
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
|
||||
|
||||
/* Set up the I2C parameters in the parameter ram. */
|
||||
out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
|
||||
out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
|
||||
|
||||
if (cpm->version == 1) {
|
||||
out_8(&i2c_ram->tfcr, I2C_EB);
|
||||
out_8(&i2c_ram->rfcr, I2C_EB);
|
||||
} else {
|
||||
out_8(&i2c_ram->tfcr, I2C_EB_CPM2);
|
||||
out_8(&i2c_ram->rfcr, I2C_EB_CPM2);
|
||||
}
|
||||
|
||||
out_be16(&i2c_ram->mrblr, CPM_MAX_READ);
|
||||
|
||||
out_be32(&i2c_ram->rstate, 0);
|
||||
out_be32(&i2c_ram->rdp, 0);
|
||||
out_be16(&i2c_ram->rbptr, 0);
|
||||
out_be16(&i2c_ram->rbc, 0);
|
||||
out_be32(&i2c_ram->rxtmp, 0);
|
||||
out_be32(&i2c_ram->tstate, 0);
|
||||
out_be32(&i2c_ram->tdp, 0);
|
||||
out_be16(&i2c_ram->tbptr, 0);
|
||||
out_be16(&i2c_ram->tbc, 0);
|
||||
out_be32(&i2c_ram->txtmp, 0);
|
||||
}
|
||||
|
||||
static void cpm_i2c_force_close(struct i2c_adapter *adap)
|
||||
{
|
||||
struct cpm_i2c *cpm = i2c_get_adapdata(adap);
|
||||
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
|
||||
|
||||
dev_dbg(&adap->dev, "cpm_i2c_force_close()\n");
|
||||
|
||||
cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
|
||||
|
||||
out_8(&i2c_reg->i2cmr, 0x00); /* Disable all interrupts */
|
||||
out_8(&i2c_reg->i2cer, 0xff);
|
||||
}
|
||||
|
||||
static void cpm_i2c_parse_message(struct i2c_adapter *adap,
|
||||
struct i2c_msg *pmsg, int num, int tx, int rx)
|
||||
{
|
||||
cbd_t __iomem *tbdf;
|
||||
cbd_t __iomem *rbdf;
|
||||
u_char addr;
|
||||
u_char *tb;
|
||||
u_char *rb;
|
||||
struct cpm_i2c *cpm = i2c_get_adapdata(adap);
|
||||
|
||||
tbdf = cpm->tbase + tx;
|
||||
rbdf = cpm->rbase + rx;
|
||||
|
||||
addr = pmsg->addr << 1;
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
|
||||
tb = cpm->txbuf[tx];
|
||||
rb = cpm->rxbuf[rx];
|
||||
|
||||
/* Align read buffer */
|
||||
rb = (u_char *) (((ulong) rb + 1) & ~1);
|
||||
|
||||
tb[0] = addr; /* Device address byte w/rw flag */
|
||||
|
||||
out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
|
||||
out_be16(&tbdf->cbd_sc, 0);
|
||||
|
||||
if (!(pmsg->flags & I2C_M_NOSTART))
|
||||
setbits16(&tbdf->cbd_sc, BD_I2C_START);
|
||||
|
||||
if (tx + 1 == num)
|
||||
setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
|
||||
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
/*
|
||||
* To read, we need an empty buffer of the proper length.
|
||||
* All that is used is the first byte for address, the remainder
|
||||
* is just used for timing (and doesn't really have to exist).
|
||||
*/
|
||||
|
||||
dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr);
|
||||
|
||||
out_be16(&rbdf->cbd_datlen, 0);
|
||||
out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
|
||||
|
||||
if (rx + 1 == CPM_MAXBD)
|
||||
setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
|
||||
|
||||
eieio();
|
||||
setbits16(&tbdf->cbd_sc, BD_SC_READY);
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "cpm_i2c_write(abyte=0x%x)\n", addr);
|
||||
|
||||
memcpy(tb+1, pmsg->buf, pmsg->len);
|
||||
|
||||
eieio();
|
||||
setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
|
||||
}
|
||||
}
|
||||
|
||||
static int cpm_i2c_check_message(struct i2c_adapter *adap,
|
||||
struct i2c_msg *pmsg, int tx, int rx)
|
||||
{
|
||||
cbd_t __iomem *tbdf;
|
||||
cbd_t __iomem *rbdf;
|
||||
u_char *tb;
|
||||
u_char *rb;
|
||||
struct cpm_i2c *cpm = i2c_get_adapdata(adap);
|
||||
|
||||
tbdf = cpm->tbase + tx;
|
||||
rbdf = cpm->rbase + rx;
|
||||
|
||||
tb = cpm->txbuf[tx];
|
||||
rb = cpm->rxbuf[rx];
|
||||
|
||||
/* Align read buffer */
|
||||
rb = (u_char *) (((uint) rb + 1) & ~1);
|
||||
|
||||
eieio();
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n",
|
||||
in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc));
|
||||
|
||||
if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
|
||||
dev_dbg(&adap->dev, "I2C read; No ack\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
|
||||
dev_err(&adap->dev,
|
||||
"I2C read; complete but rbuf empty\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
|
||||
dev_err(&adap->dev, "I2C read; Overrun\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
memcpy(pmsg->buf, rb, pmsg->len);
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx,
|
||||
in_be16(&tbdf->cbd_sc));
|
||||
|
||||
if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
|
||||
dev_dbg(&adap->dev, "I2C write; No ack\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
|
||||
dev_err(&adap->dev, "I2C write; Underrun\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
|
||||
dev_err(&adap->dev, "I2C write; Collision\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct cpm_i2c *cpm = i2c_get_adapdata(adap);
|
||||
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
|
||||
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
|
||||
struct i2c_msg *pmsg;
|
||||
int ret, i;
|
||||
int tptr;
|
||||
int rptr;
|
||||
cbd_t __iomem *tbdf;
|
||||
cbd_t __iomem *rbdf;
|
||||
|
||||
if (num > CPM_MAXBD)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if we have any oversized READ requests */
|
||||
for (i = 0; i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
if (pmsg->len >= CPM_MAX_READ)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Reset to use first buffer */
|
||||
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
|
||||
out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
|
||||
|
||||
tbdf = cpm->tbase;
|
||||
rbdf = cpm->rbase;
|
||||
|
||||
tptr = 0;
|
||||
rptr = 0;
|
||||
|
||||
while (tptr < num) {
|
||||
pmsg = &msgs[tptr];
|
||||
dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
|
||||
|
||||
cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr);
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
rptr++;
|
||||
tptr++;
|
||||
}
|
||||
/* Start transfer now */
|
||||
/* Enable RX/TX/Error interupts */
|
||||
out_8(&i2c_reg->i2cmr, I2CER_TXE | I2CER_TXB | I2CER_RXB);
|
||||
out_8(&i2c_reg->i2cer, 0xff); /* Clear interrupt status */
|
||||
/* Chip bug, set enable here */
|
||||
setbits8(&i2c_reg->i2mod, I2MOD_EN); /* Enable */
|
||||
/* Begin transmission */
|
||||
setbits8(&i2c_reg->i2com, I2COM_START);
|
||||
|
||||
tptr = 0;
|
||||
rptr = 0;
|
||||
|
||||
while (tptr < num) {
|
||||
/* Check for outstanding messages */
|
||||
dev_dbg(&adap->dev, "test ready.\n");
|
||||
pmsg = &msgs[tptr];
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
ret = wait_event_interruptible_timeout(cpm->i2c_wait,
|
||||
!(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
|
||||
1 * HZ);
|
||||
else
|
||||
ret = wait_event_interruptible_timeout(cpm->i2c_wait,
|
||||
!(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
|
||||
1 * HZ);
|
||||
if (ret == 0) {
|
||||
ret = -EREMOTEIO;
|
||||
dev_err(&adap->dev, "I2C transfer: timeout\n");
|
||||
goto out_err;
|
||||
}
|
||||
if (ret > 0) {
|
||||
dev_dbg(&adap->dev, "ready.\n");
|
||||
ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr);
|
||||
tptr++;
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
rptr++;
|
||||
if (ret)
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
#ifdef I2C_CHIP_ERRATA
|
||||
/*
|
||||
* Chip errata, clear enable. This is not needed on rev D4 CPUs.
|
||||
* Disabling I2C too early may cause too short stop condition
|
||||
*/
|
||||
udelay(4);
|
||||
clrbits8(&i2c_reg->i2mod, I2MOD_EN);
|
||||
#endif
|
||||
return (num);
|
||||
|
||||
out_err:
|
||||
cpm_i2c_force_close(adap);
|
||||
#ifdef I2C_CHIP_ERRATA
|
||||
/*
|
||||
* Chip errata, clear enable. This is not needed on rev D4 CPUs.
|
||||
*/
|
||||
clrbits8(&i2c_reg->i2mod, I2MOD_EN);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 cpm_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static const struct i2c_algorithm cpm_i2c_algo = {
|
||||
.master_xfer = cpm_i2c_xfer,
|
||||
.functionality = cpm_i2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter cpm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-cpm",
|
||||
.algo = &cpm_i2c_algo,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
};
|
||||
|
||||
static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
|
||||
{
|
||||
struct of_device *ofdev = cpm->ofdev;
|
||||
const u32 *data;
|
||||
int len, ret, i;
|
||||
void __iomem *i2c_base;
|
||||
cbd_t __iomem *tbdf;
|
||||
cbd_t __iomem *rbdf;
|
||||
unsigned char brg;
|
||||
|
||||
dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");
|
||||
|
||||
init_waitqueue_head(&cpm->i2c_wait);
|
||||
|
||||
cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
|
||||
if (cpm->irq == NO_IRQ)
|
||||
return -EINVAL;
|
||||
|
||||
/* Install interrupt handler. */
|
||||
ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
|
||||
&cpm->adap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* I2C parameter RAM */
|
||||
i2c_base = of_iomap(ofdev->node, 1);
|
||||
if (i2c_base == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out_irq;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(ofdev->node, "fsl,cpm1-i2c")) {
|
||||
|
||||
/* Check for and use a microcode relocation patch. */
|
||||
cpm->i2c_ram = i2c_base;
|
||||
cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);
|
||||
|
||||
/*
|
||||
* Maybe should use cpm_muram_alloc instead of hardcoding
|
||||
* this in micropatch.c
|
||||
*/
|
||||
if (cpm->i2c_addr) {
|
||||
cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
|
||||
iounmap(i2c_base);
|
||||
}
|
||||
|
||||
cpm->version = 1;
|
||||
|
||||
} else if (of_device_is_compatible(ofdev->node, "fsl,cpm2-i2c")) {
|
||||
cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
|
||||
cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
|
||||
out_be16(i2c_base, cpm->i2c_addr);
|
||||
iounmap(i2c_base);
|
||||
|
||||
cpm->version = 2;
|
||||
|
||||
} else {
|
||||
iounmap(i2c_base);
|
||||
ret = -EINVAL;
|
||||
goto out_irq;
|
||||
}
|
||||
|
||||
/* I2C control/status registers */
|
||||
cpm->i2c_reg = of_iomap(ofdev->node, 0);
|
||||
if (cpm->i2c_reg == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out_ram;
|
||||
}
|
||||
|
||||
data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
|
||||
if (!data || len != 4) {
|
||||
ret = -EINVAL;
|
||||
goto out_reg;
|
||||
}
|
||||
cpm->cp_command = *data;
|
||||
|
||||
data = of_get_property(ofdev->node, "linux,i2c-class", &len);
|
||||
if (data && len == 4)
|
||||
cpm->adap.class = *data;
|
||||
|
||||
data = of_get_property(ofdev->node, "clock-frequency", &len);
|
||||
if (data && len == 4)
|
||||
cpm->freq = *data;
|
||||
else
|
||||
cpm->freq = 60000; /* use 60kHz i2c clock by default */
|
||||
|
||||
/*
|
||||
* Allocate space for CPM_MAXBD transmit and receive buffer
|
||||
* descriptors in the DP ram.
|
||||
*/
|
||||
cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
|
||||
if (!cpm->dp_addr) {
|
||||
ret = -ENOMEM;
|
||||
goto out_reg;
|
||||
}
|
||||
|
||||
cpm->tbase = cpm_muram_addr(cpm->dp_addr);
|
||||
cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
|
||||
|
||||
/* Allocate TX and RX buffers */
|
||||
|
||||
tbdf = cpm->tbase;
|
||||
rbdf = cpm->rbase;
|
||||
|
||||
for (i = 0; i < CPM_MAXBD; i++) {
|
||||
cpm->rxbuf[i] = dma_alloc_coherent(
|
||||
NULL, CPM_MAX_READ + 1, &cpm->rxdma[i], GFP_KERNEL);
|
||||
if (!cpm->rxbuf[i]) {
|
||||
ret = -ENOMEM;
|
||||
goto out_muram;
|
||||
}
|
||||
out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
|
||||
|
||||
cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(
|
||||
NULL, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
|
||||
if (!cpm->txbuf[i]) {
|
||||
ret = -ENOMEM;
|
||||
goto out_muram;
|
||||
}
|
||||
out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
|
||||
}
|
||||
|
||||
/* Initialize Tx/Rx parameters. */
|
||||
|
||||
cpm_reset_i2c_params(cpm);
|
||||
|
||||
dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n",
|
||||
cpm->i2c_ram, cpm->i2c_addr, cpm->freq);
|
||||
dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
|
||||
(u8 __iomem *)cpm->tbase - DPRAM_BASE,
|
||||
(u8 __iomem *)cpm->rbase - DPRAM_BASE);
|
||||
|
||||
cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
|
||||
|
||||
/*
|
||||
* Select an invalid address. Just make sure we don't use loopback mode
|
||||
*/
|
||||
out_8(&cpm->i2c_reg->i2add, 0x7f << 1);
|
||||
|
||||
/*
|
||||
* PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
|
||||
* i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
|
||||
* the actual i2c bus frequency.
|
||||
*/
|
||||
brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3;
|
||||
out_8(&cpm->i2c_reg->i2brg, brg);
|
||||
|
||||
out_8(&cpm->i2c_reg->i2mod, 0x00);
|
||||
out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Master mode */
|
||||
|
||||
/* Disable interrupts. */
|
||||
out_8(&cpm->i2c_reg->i2cmr, 0);
|
||||
out_8(&cpm->i2c_reg->i2cer, 0xff);
|
||||
|
||||
return 0;
|
||||
|
||||
out_muram:
|
||||
for (i = 0; i < CPM_MAXBD; i++) {
|
||||
if (cpm->rxbuf[i])
|
||||
dma_free_coherent(NULL, CPM_MAX_READ + 1,
|
||||
cpm->rxbuf[i], cpm->rxdma[i]);
|
||||
if (cpm->txbuf[i])
|
||||
dma_free_coherent(NULL, CPM_MAX_READ + 1,
|
||||
cpm->txbuf[i], cpm->txdma[i]);
|
||||
}
|
||||
cpm_muram_free(cpm->dp_addr);
|
||||
out_reg:
|
||||
iounmap(cpm->i2c_reg);
|
||||
out_ram:
|
||||
if ((cpm->version == 1) && (!cpm->i2c_addr))
|
||||
iounmap(cpm->i2c_ram);
|
||||
if (cpm->version == 2)
|
||||
cpm_muram_free(cpm->i2c_addr);
|
||||
out_irq:
|
||||
free_irq(cpm->irq, &cpm->adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Shut down I2C. */
|
||||
clrbits8(&cpm->i2c_reg->i2mod, I2MOD_EN);
|
||||
|
||||
/* Disable interrupts */
|
||||
out_8(&cpm->i2c_reg->i2cmr, 0);
|
||||
out_8(&cpm->i2c_reg->i2cer, 0xff);
|
||||
|
||||
free_irq(cpm->irq, &cpm->adap);
|
||||
|
||||
/* Free all memory */
|
||||
for (i = 0; i < CPM_MAXBD; i++) {
|
||||
dma_free_coherent(NULL, CPM_MAX_READ + 1,
|
||||
cpm->rxbuf[i], cpm->rxdma[i]);
|
||||
dma_free_coherent(NULL, CPM_MAX_READ + 1,
|
||||
cpm->txbuf[i], cpm->txdma[i]);
|
||||
}
|
||||
|
||||
cpm_muram_free(cpm->dp_addr);
|
||||
iounmap(cpm->i2c_reg);
|
||||
|
||||
if ((cpm->version == 1) && (!cpm->i2c_addr))
|
||||
iounmap(cpm->i2c_ram);
|
||||
if (cpm->version == 2)
|
||||
cpm_muram_free(cpm->i2c_addr);
|
||||
}
|
||||
|
||||
static int __devinit cpm_i2c_probe(struct of_device *ofdev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
int result, len;
|
||||
struct cpm_i2c *cpm;
|
||||
const u32 *data;
|
||||
|
||||
cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL);
|
||||
if (!cpm)
|
||||
return -ENOMEM;
|
||||
|
||||
cpm->ofdev = ofdev;
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, cpm);
|
||||
|
||||
cpm->adap = cpm_ops;
|
||||
i2c_set_adapdata(&cpm->adap, cpm);
|
||||
cpm->adap.dev.parent = &ofdev->dev;
|
||||
|
||||
result = cpm_i2c_setup(cpm);
|
||||
if (result) {
|
||||
dev_err(&ofdev->dev, "Unable to init hardware\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
|
||||
data = of_get_property(ofdev->node, "linux,i2c-index", &len);
|
||||
if (data && len == 4) {
|
||||
cpm->adap.nr = *data;
|
||||
result = i2c_add_numbered_adapter(&cpm->adap);
|
||||
} else
|
||||
result = i2c_add_adapter(&cpm->adap);
|
||||
|
||||
if (result < 0) {
|
||||
dev_err(&ofdev->dev, "Unable to register with I2C\n");
|
||||
goto out_shut;
|
||||
}
|
||||
|
||||
dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
|
||||
cpm->adap.name);
|
||||
|
||||
/*
|
||||
* register OF I2C devices
|
||||
*/
|
||||
of_register_i2c_devices(&cpm->adap, ofdev->node);
|
||||
|
||||
return 0;
|
||||
out_shut:
|
||||
cpm_i2c_shutdown(cpm);
|
||||
out_free:
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
kfree(cpm);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int __devexit cpm_i2c_remove(struct of_device *ofdev)
|
||||
{
|
||||
struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
|
||||
|
||||
i2c_del_adapter(&cpm->adap);
|
||||
|
||||
cpm_i2c_shutdown(cpm);
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
kfree(cpm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cpm_i2c_match[] = {
|
||||
{
|
||||
.compatible = "fsl,cpm1-i2c",
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,cpm2-i2c",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, cpm_i2c_match);
|
||||
|
||||
static struct of_platform_driver cpm_i2c_driver = {
|
||||
.match_table = cpm_i2c_match,
|
||||
.probe = cpm_i2c_probe,
|
||||
.remove = __devexit_p(cpm_i2c_remove),
|
||||
.driver = {
|
||||
.name = "fsl-i2c-cpm",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init cpm_i2c_init(void)
|
||||
{
|
||||
return of_register_platform_driver(&cpm_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit cpm_i2c_exit(void)
|
||||
{
|
||||
of_unregister_platform_driver(&cpm_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(cpm_i2c_init);
|
||||
module_exit(cpm_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -85,6 +85,7 @@
|
|||
#define DAVINCI_I2C_MDR_MST (1 << 10)
|
||||
#define DAVINCI_I2C_MDR_TRX (1 << 9)
|
||||
#define DAVINCI_I2C_MDR_XA (1 << 8)
|
||||
#define DAVINCI_I2C_MDR_RM (1 << 7)
|
||||
#define DAVINCI_I2C_MDR_IRS (1 << 5)
|
||||
|
||||
#define DAVINCI_I2C_IMR_AAS (1 << 6)
|
||||
|
@ -112,6 +113,7 @@ struct davinci_i2c_dev {
|
|||
u8 *buf;
|
||||
size_t buf_len;
|
||||
int irq;
|
||||
u8 terminate;
|
||||
struct i2c_adapter adapter;
|
||||
};
|
||||
|
||||
|
@ -142,6 +144,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
|
|||
struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
|
||||
u16 psc;
|
||||
u32 clk;
|
||||
u32 d;
|
||||
u32 clkh;
|
||||
u32 clkl;
|
||||
u32 input_clock = clk_get_rate(dev->clk);
|
||||
|
@ -171,23 +174,29 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
|
|||
* if PSC > 1 , d = 5
|
||||
*/
|
||||
|
||||
psc = 26; /* To get 1MHz clock */
|
||||
/* get minimum of 7 MHz clock, but max of 12 MHz */
|
||||
psc = (input_clock / 7000000) - 1;
|
||||
if ((input_clock / (psc + 1)) > 12000000)
|
||||
psc++; /* better to run under spec than over */
|
||||
d = (psc >= 2) ? 5 : 7 - psc;
|
||||
|
||||
clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10;
|
||||
clkh = (50 * clk) / 100;
|
||||
clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - (d << 1);
|
||||
clkh = clk >> 1;
|
||||
clkl = clk - clkh;
|
||||
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
|
||||
|
||||
dev_dbg(dev->dev, "CLK = %d\n", clk);
|
||||
dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
|
||||
dev_dbg(dev->dev, "PSC = %d\n",
|
||||
davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
|
||||
dev_dbg(dev->dev, "CLKL = %d\n",
|
||||
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
|
||||
dev_dbg(dev->dev, "CLKH = %d\n",
|
||||
davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
|
||||
dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
|
||||
pdata->bus_freq, pdata->bus_delay);
|
||||
|
||||
/* Take the I2C module out of reset: */
|
||||
w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
||||
|
@ -233,7 +242,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
|||
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
|
||||
u32 flag;
|
||||
u32 stat;
|
||||
u16 w;
|
||||
int r;
|
||||
|
||||
|
@ -254,12 +262,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
|||
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
INIT_COMPLETION(dev->cmd_complete);
|
||||
dev->cmd_err = 0;
|
||||
|
||||
/* Clear any pending interrupts by reading the IVR */
|
||||
stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG);
|
||||
|
||||
/* Take I2C out of reset, configure it as master and set the
|
||||
* start bit */
|
||||
flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT;
|
||||
|
@ -280,20 +285,34 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
|||
MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
|
||||
|
||||
dev->terminate = 0;
|
||||
/* write the data into mode register */
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
||||
|
||||
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
|
||||
DAVINCI_I2C_TIMEOUT);
|
||||
dev->buf_len = 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 0) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
i2c_davinci_init(dev);
|
||||
dev->buf_len = 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (dev->buf_len) {
|
||||
/* This should be 0 if all bytes were transferred
|
||||
* or dev->cmd_err denotes an error.
|
||||
* A signal may have aborted the transfer.
|
||||
*/
|
||||
if (r >= 0) {
|
||||
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
|
||||
dev->buf_len);
|
||||
r = -EREMOTEIO;
|
||||
}
|
||||
dev->terminate = 1;
|
||||
wmb();
|
||||
dev->buf_len = 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* no error */
|
||||
if (likely(!dev->cmd_err))
|
||||
|
@ -338,12 +357,11 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
|
||||
dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,
|
||||
ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(dev->dev, "%s:%d ret: %d\n", __func__, __LINE__, ret);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
@ -352,6 +370,27 @@ static u32 i2c_davinci_func(struct i2c_adapter *adap)
|
|||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
static void terminate_read(struct davinci_i2c_dev *dev)
|
||||
{
|
||||
u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
||||
w |= DAVINCI_I2C_MDR_NACK;
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
|
||||
|
||||
/* Throw away data */
|
||||
davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
|
||||
if (!dev->terminate)
|
||||
dev_err(dev->dev, "RDR IRQ while no data requested\n");
|
||||
}
|
||||
static void terminate_write(struct davinci_i2c_dev *dev)
|
||||
{
|
||||
u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
||||
w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
|
||||
|
||||
if (!dev->terminate)
|
||||
dev_err(dev->dev, "TDR IRQ while no data to send\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt service routine. This gets called whenever an I2C interrupt
|
||||
* occurs.
|
||||
|
@ -372,12 +411,15 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|||
|
||||
switch (stat) {
|
||||
case DAVINCI_I2C_IVR_AL:
|
||||
/* Arbitration lost, must retry */
|
||||
dev->cmd_err |= DAVINCI_I2C_STR_AL;
|
||||
dev->buf_len = 0;
|
||||
complete(&dev->cmd_complete);
|
||||
break;
|
||||
|
||||
case DAVINCI_I2C_IVR_NACK:
|
||||
dev->cmd_err |= DAVINCI_I2C_STR_NACK;
|
||||
dev->buf_len = 0;
|
||||
complete(&dev->cmd_complete);
|
||||
break;
|
||||
|
||||
|
@ -399,9 +441,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|||
davinci_i2c_write_reg(dev,
|
||||
DAVINCI_I2C_STR_REG,
|
||||
DAVINCI_I2C_IMR_RRDY);
|
||||
} else
|
||||
dev_err(dev->dev, "RDR IRQ while no "
|
||||
"data requested\n");
|
||||
} else {
|
||||
/* signal can terminate transfer */
|
||||
terminate_read(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case DAVINCI_I2C_IVR_XRDY:
|
||||
|
@ -418,9 +461,10 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
|
|||
davinci_i2c_write_reg(dev,
|
||||
DAVINCI_I2C_IMR_REG,
|
||||
w);
|
||||
} else
|
||||
dev_err(dev->dev, "TDR IRQ while no data to "
|
||||
"send\n");
|
||||
} else {
|
||||
/* signal can terminate transfer */
|
||||
terminate_write(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case DAVINCI_I2C_IVR_SCD:
|
||||
|
@ -475,6 +519,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|||
goto err_release_region;
|
||||
}
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
dev->dev = get_device(&pdev->dev);
|
||||
dev->irq = irq->start;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
|
|
@ -196,13 +196,11 @@ static struct i2c_algo_pcf_data pcf_isa_data = {
|
|||
.getown = pcf_isa_getown,
|
||||
.getclock = pcf_isa_getclock,
|
||||
.waitforpin = pcf_isa_waitforpin,
|
||||
.udelay = 10,
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
static struct i2c_adapter pcf_isa_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.id = I2C_HW_P_ELEK,
|
||||
.algo_data = &pcf_isa_data,
|
||||
.name = "i2c-elektor",
|
||||
|
|
|
@ -140,7 +140,7 @@ static int __init i2c_gpio_probe(struct platform_device *pdev)
|
|||
adap->owner = THIS_MODULE;
|
||||
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
|
||||
adap->algo_data = bit_data;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
i2c-hydra.c - Part of lm_sensors, Linux kernel modules
|
||||
for hardware monitoring
|
||||
|
||||
i2c Support for the Apple `Hydra' Mac I/O
|
||||
|
||||
Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
/*
|
||||
i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
|
||||
<mdsxyz123@yahoo.com>
|
||||
Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
|
||||
Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -64,6 +62,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* I801 SMBus address offsets */
|
||||
|
@ -121,6 +120,10 @@
|
|||
#define SMBHSTSTS_INTR 0x02
|
||||
#define SMBHSTSTS_HOST_BUSY 0x01
|
||||
|
||||
#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
|
||||
SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
|
||||
SMBHSTSTS_INTR)
|
||||
|
||||
static unsigned long i801_smba;
|
||||
static unsigned char i801_original_hstcfg;
|
||||
static struct pci_driver i801_driver;
|
||||
|
@ -132,31 +135,96 @@ static struct pci_dev *I801_dev;
|
|||
#define FEATURE_I2C_BLOCK_READ (1 << 3)
|
||||
static unsigned int i801_features;
|
||||
|
||||
static int i801_transaction(int xact)
|
||||
/* Make sure the SMBus host is ready to start transmitting.
|
||||
Return 0 if it is, -EBUSY if it is not. */
|
||||
static int i801_check_pre(void)
|
||||
{
|
||||
int temp;
|
||||
int result = 0;
|
||||
int timeout = 0;
|
||||
int status;
|
||||
|
||||
dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||
inb_p(SMBHSTDAT1));
|
||||
status = inb_p(SMBHSTSTS);
|
||||
if (status & SMBHSTSTS_HOST_BUSY) {
|
||||
dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Make sure the SMBus host is ready to start transmitting */
|
||||
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
|
||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n",
|
||||
temp);
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||
dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
|
||||
return -1;
|
||||
} else {
|
||||
dev_dbg(&I801_dev->dev, "Successful!\n");
|
||||
status &= STATUS_FLAGS;
|
||||
if (status) {
|
||||
dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
|
||||
status);
|
||||
outb_p(status, SMBHSTSTS);
|
||||
status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
|
||||
if (status) {
|
||||
dev_err(&I801_dev->dev,
|
||||
"Failed clearing status flags (%02x)\n",
|
||||
status);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert the status register to an error code, and clear it. */
|
||||
static int i801_check_post(int status, int timeout)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout) {
|
||||
dev_err(&I801_dev->dev, "Transaction timeout\n");
|
||||
/* 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);
|
||||
|
||||
/* Check if it worked */
|
||||
status = inb_p(SMBHSTSTS);
|
||||
if ((status & SMBHSTSTS_HOST_BUSY) ||
|
||||
!(status & SMBHSTSTS_FAILED))
|
||||
dev_err(&I801_dev->dev,
|
||||
"Failed terminating the transaction\n");
|
||||
outb_p(STATUS_FLAGS, SMBHSTSTS);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (status & SMBHSTSTS_FAILED) {
|
||||
result = -EIO;
|
||||
dev_err(&I801_dev->dev, "Transaction failed\n");
|
||||
}
|
||||
if (status & SMBHSTSTS_DEV_ERR) {
|
||||
result = -ENXIO;
|
||||
dev_dbg(&I801_dev->dev, "No response\n");
|
||||
}
|
||||
if (status & SMBHSTSTS_BUS_ERR) {
|
||||
result = -EAGAIN;
|
||||
dev_dbg(&I801_dev->dev, "Lost arbitration\n");
|
||||
}
|
||||
|
||||
if (result) {
|
||||
/* Clear error flags */
|
||||
outb_p(status & STATUS_FLAGS, SMBHSTSTS);
|
||||
status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
|
||||
if (status) {
|
||||
dev_warn(&I801_dev->dev, "Failed clearing status "
|
||||
"flags at end of transaction (%02x)\n",
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int i801_transaction(int xact)
|
||||
{
|
||||
int status;
|
||||
int result;
|
||||
int timeout = 0;
|
||||
|
||||
result = i801_check_pre();
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
|
||||
* INTREN, SMBSCMD are passed in xact */
|
||||
outb_p(xact | I801_START, SMBHSTCNT);
|
||||
|
@ -164,73 +232,40 @@ static int i801_transaction(int xact)
|
|||
/* We will always wait for a fraction of a second! */
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
} while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
|
||||
status = inb_p(SMBHSTSTS);
|
||||
} while ((status & 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);
|
||||
}
|
||||
result = i801_check_post(status, timeout >= MAX_TIMEOUT);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (temp & SMBHSTSTS_FAILED) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
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 & SMBHSTSTS_DEV_ERR) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: no response!\n");
|
||||
}
|
||||
|
||||
if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
|
||||
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
|
||||
|
||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||
dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
|
||||
"(%02x)\n", temp);
|
||||
}
|
||||
dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||
inb_p(SMBHSTDAT1));
|
||||
return result;
|
||||
outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait for INTR bit as advised by Intel */
|
||||
static void i801_wait_hwpec(void)
|
||||
{
|
||||
int timeout = 0;
|
||||
int temp;
|
||||
int status;
|
||||
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
} while ((!(temp & SMBHSTSTS_INTR))
|
||||
status = inb_p(SMBHSTSTS);
|
||||
} while ((!(status & SMBHSTSTS_INTR))
|
||||
&& (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
|
||||
}
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
outb_p(status, SMBHSTSTS);
|
||||
}
|
||||
|
||||
static int i801_block_transaction_by_block(union i2c_smbus_data *data,
|
||||
char read_write, int hwpec)
|
||||
{
|
||||
int i, len;
|
||||
int status;
|
||||
|
||||
inb_p(SMBHSTCNT); /* reset the data buffer index */
|
||||
|
||||
|
@ -242,14 +277,15 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data,
|
|||
outb_p(data->block[i+1], SMBBLKDAT);
|
||||
}
|
||||
|
||||
if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
|
||||
I801_PEC_EN * hwpec))
|
||||
return -1;
|
||||
status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
|
||||
I801_PEC_EN * hwpec);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
len = inb_p(SMBHSTDAT0);
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -1;
|
||||
return -EPROTO;
|
||||
|
||||
data->block[0] = len;
|
||||
for (i = 0; i < len; i++)
|
||||
|
@ -264,10 +300,13 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
|
|||
{
|
||||
int i, len;
|
||||
int smbcmd;
|
||||
int temp;
|
||||
int result = 0;
|
||||
int status;
|
||||
int result;
|
||||
int timeout;
|
||||
unsigned char errmask;
|
||||
|
||||
result = i801_check_pre();
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
len = data->block[0];
|
||||
|
||||
|
@ -291,36 +330,6 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
|
|||
}
|
||||
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
|
||||
|
||||
dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
|
||||
inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
|
||||
inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
|
||||
|
||||
/* Make sure the SMBus host is ready to start transmitting */
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
if (i == 1) {
|
||||
/* Erroneous conditions before transaction:
|
||||
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
|
||||
errmask = 0x9f;
|
||||
} else {
|
||||
/* Erroneous conditions during transaction:
|
||||
* Failed, Bus_Err, Dev_Err, Intr */
|
||||
errmask = 0x1e;
|
||||
}
|
||||
if (temp & errmask) {
|
||||
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
|
||||
"Resetting...\n", temp);
|
||||
outb_p(temp, SMBHSTSTS);
|
||||
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
|
||||
dev_err(&I801_dev->dev,
|
||||
"Reset failed! (%02x)\n", temp);
|
||||
return -1;
|
||||
}
|
||||
if (i != 1)
|
||||
/* if die in middle of block transaction, fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
|
||||
|
||||
|
@ -328,41 +337,28 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
|
|||
timeout = 0;
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb_p(SMBHSTSTS);
|
||||
status = inb_p(SMBHSTSTS);
|
||||
}
|
||||
while ((!(temp & SMBHSTSTS_BYTE_DONE))
|
||||
while ((!(status & 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 & SMBHSTSTS_FAILED) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev,
|
||||
"Error: Failed bus transaction\n");
|
||||
} else if (temp & SMBHSTSTS_BUS_ERR) {
|
||||
result = -1;
|
||||
dev_err(&I801_dev->dev, "Bus collision!\n");
|
||||
} else if (temp & SMBHSTSTS_DEV_ERR) {
|
||||
result = -1;
|
||||
dev_dbg(&I801_dev->dev, "Error: no response!\n");
|
||||
}
|
||||
result = i801_check_post(status, timeout >= MAX_TIMEOUT);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (i == 1 && read_write == I2C_SMBUS_READ
|
||||
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
len = inb_p(SMBHSTDAT0);
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -1;
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
|
||||
dev_err(&I801_dev->dev,
|
||||
"Illegal SMBus block read size %d\n",
|
||||
len);
|
||||
/* Recover */
|
||||
while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
|
||||
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
|
||||
outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
|
||||
return -EPROTO;
|
||||
}
|
||||
data->block[0] = len;
|
||||
}
|
||||
|
||||
|
@ -371,30 +367,19 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
|
|||
data->block[i] = inb_p(SMBBLKDAT);
|
||||
if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
|
||||
outb_p(data->block[i+1], SMBBLKDAT);
|
||||
if ((temp & 0x9e) != 0x00)
|
||||
outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
|
||||
|
||||
if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
|
||||
dev_dbg(&I801_dev->dev,
|
||||
"Bad status (%02x) at end of transaction\n",
|
||||
temp);
|
||||
}
|
||||
dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
|
||||
inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
|
||||
inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
/* signals SMBBLKDAT ready */
|
||||
outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
|
||||
}
|
||||
return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -414,7 +399,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||
} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
|
||||
dev_err(&I801_dev->dev,
|
||||
"I2C block read is unsupported!\n");
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,7 +434,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 i801_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write, u8 command,
|
||||
int size, union i2c_smbus_data * data)
|
||||
|
@ -511,10 +496,9 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
|
|||
outb_p(command, SMBHSTCMD);
|
||||
block = 1;
|
||||
break;
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
default:
|
||||
dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (hwpec) /* enable/disable hardware PEC */
|
||||
|
@ -537,7 +521,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
|
|||
if(block)
|
||||
return ret;
|
||||
if(ret)
|
||||
return -1;
|
||||
return ret;
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
|
||||
return 0;
|
||||
|
||||
|
@ -572,7 +556,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter i801_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_I801,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
@ -639,6 +623,10 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
|
|||
goto exit;
|
||||
}
|
||||
|
||||
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
err = pci_request_region(dev, SMBBAR, i801_driver.name);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to request SMBus region "
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Ralph Metzler <rjkm@thp.uni-koeln.de>, and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
|
||||
Simon Vogl
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
This interfaces to the I810/I815 to provide access to
|
||||
the DDC Bus and the I2C Bus.
|
||||
|
||||
SUPPORTED DEVICES PCI ID
|
||||
i810AA 7121
|
||||
i810AB 7123
|
||||
i810E 7125
|
||||
i815 1132
|
||||
i845G 2562
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* GPIO register locations */
|
||||
#define I810_IOCONTROL_OFFSET 0x5000
|
||||
#define I810_HVSYNC 0x00 /* not used */
|
||||
#define I810_GPIOA 0x10
|
||||
#define I810_GPIOB 0x14
|
||||
|
||||
/* bit locations in the registers */
|
||||
#define SCL_DIR_MASK 0x0001
|
||||
#define SCL_DIR 0x0002
|
||||
#define SCL_VAL_MASK 0x0004
|
||||
#define SCL_VAL_OUT 0x0008
|
||||
#define SCL_VAL_IN 0x0010
|
||||
#define SDA_DIR_MASK 0x0100
|
||||
#define SDA_DIR 0x0200
|
||||
#define SDA_VAL_MASK 0x0400
|
||||
#define SDA_VAL_OUT 0x0800
|
||||
#define SDA_VAL_IN 0x1000
|
||||
|
||||
/* initialization states */
|
||||
#define INIT1 0x1
|
||||
#define INIT2 0x2
|
||||
#define INIT3 0x4
|
||||
|
||||
/* delays */
|
||||
#define CYCLE_DELAY 10
|
||||
#define TIMEOUT (HZ / 2)
|
||||
|
||||
static void __iomem *ioaddr;
|
||||
|
||||
/* The i810 GPIO registers have individual masks for each bit
|
||||
so we never have to read before writing. Nice. */
|
||||
|
||||
static void bit_i810i2c_setscl(void *data, int val)
|
||||
{
|
||||
writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
|
||||
ioaddr + I810_GPIOB);
|
||||
readl(ioaddr + I810_GPIOB); /* flush posted write */
|
||||
}
|
||||
|
||||
static void bit_i810i2c_setsda(void *data, int val)
|
||||
{
|
||||
writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
|
||||
ioaddr + I810_GPIOB);
|
||||
readl(ioaddr + I810_GPIOB); /* flush posted write */
|
||||
}
|
||||
|
||||
/* The GPIO pins are open drain, so the pins could always remain outputs.
|
||||
However, some chip versions don't latch the inputs unless they
|
||||
are set as inputs.
|
||||
We rely on the i2c-algo-bit routines to set the pins high before
|
||||
reading the input from other chips. Following guidance in the 815
|
||||
prog. ref. guide, we do a "dummy write" of 0 to the register before
|
||||
reading which forces the input value to be latched. We presume this
|
||||
applies to the 810 as well; shouldn't hurt anyway. This is necessary to get
|
||||
i2c_algo_bit bit_test=1 to pass. */
|
||||
|
||||
static int bit_i810i2c_getscl(void *data)
|
||||
{
|
||||
writel(SCL_DIR_MASK, ioaddr + I810_GPIOB);
|
||||
writel(0, ioaddr + I810_GPIOB);
|
||||
return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN));
|
||||
}
|
||||
|
||||
static int bit_i810i2c_getsda(void *data)
|
||||
{
|
||||
writel(SDA_DIR_MASK, ioaddr + I810_GPIOB);
|
||||
writel(0, ioaddr + I810_GPIOB);
|
||||
return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN));
|
||||
}
|
||||
|
||||
static void bit_i810ddc_setscl(void *data, int val)
|
||||
{
|
||||
writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
|
||||
ioaddr + I810_GPIOA);
|
||||
readl(ioaddr + I810_GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static void bit_i810ddc_setsda(void *data, int val)
|
||||
{
|
||||
writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
|
||||
ioaddr + I810_GPIOA);
|
||||
readl(ioaddr + I810_GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static int bit_i810ddc_getscl(void *data)
|
||||
{
|
||||
writel(SCL_DIR_MASK, ioaddr + I810_GPIOA);
|
||||
writel(0, ioaddr + I810_GPIOA);
|
||||
return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN));
|
||||
}
|
||||
|
||||
static int bit_i810ddc_getsda(void *data)
|
||||
{
|
||||
writel(SDA_DIR_MASK, ioaddr + I810_GPIOA);
|
||||
writel(0, ioaddr + I810_GPIOA);
|
||||
return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN));
|
||||
}
|
||||
|
||||
static int config_i810(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long cadr;
|
||||
|
||||
/* map I810 memory */
|
||||
cadr = dev->resource[1].start;
|
||||
cadr += I810_IOCONTROL_OFFSET;
|
||||
cadr &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
ioaddr = ioremap_nocache(cadr, 0x1000);
|
||||
if (ioaddr) {
|
||||
bit_i810i2c_setscl(NULL, 1);
|
||||
bit_i810i2c_setsda(NULL, 1);
|
||||
bit_i810ddc_setscl(NULL, 1);
|
||||
bit_i810ddc_setsda(NULL, 1);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct i2c_algo_bit_data i810_i2c_bit_data = {
|
||||
.setsda = bit_i810i2c_setsda,
|
||||
.setscl = bit_i810i2c_setscl,
|
||||
.getsda = bit_i810i2c_getsda,
|
||||
.getscl = bit_i810i2c_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT,
|
||||
};
|
||||
|
||||
static struct i2c_adapter i810_i2c_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_B_I810,
|
||||
.name = "I810/I815 I2C Adapter",
|
||||
.algo_data = &i810_i2c_bit_data,
|
||||
};
|
||||
|
||||
static struct i2c_algo_bit_data i810_ddc_bit_data = {
|
||||
.setsda = bit_i810ddc_setsda,
|
||||
.setscl = bit_i810ddc_setscl,
|
||||
.getsda = bit_i810ddc_getsda,
|
||||
.getscl = bit_i810ddc_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT,
|
||||
};
|
||||
|
||||
static struct i2c_adapter i810_ddc_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_B_I810,
|
||||
.name = "I810/I815 DDC Adapter",
|
||||
.algo_data = &i810_ddc_bit_data,
|
||||
};
|
||||
|
||||
static struct pci_device_id i810_ids[] __devinitdata = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG) },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (pci, i810_ids);
|
||||
|
||||
static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = config_i810(dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
dev_info(&dev->dev, "i810/i815 i2c device found.\n");
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
i810_i2c_adapter.dev.parent = &dev->dev;
|
||||
i810_ddc_adapter.dev.parent = &dev->dev;
|
||||
|
||||
retval = i2c_bit_add_bus(&i810_i2c_adapter);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = i2c_bit_add_bus(&i810_ddc_adapter);
|
||||
if (retval)
|
||||
i2c_del_adapter(&i810_i2c_adapter);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __devexit i810_remove(struct pci_dev *dev)
|
||||
{
|
||||
i2c_del_adapter(&i810_ddc_adapter);
|
||||
i2c_del_adapter(&i810_i2c_adapter);
|
||||
iounmap(ioaddr);
|
||||
}
|
||||
|
||||
static struct pci_driver i810_driver = {
|
||||
.name = "i810_smbus",
|
||||
.id_table = i810_ids,
|
||||
.probe = i810_probe,
|
||||
.remove = __devexit_p(i810_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_i810_init(void)
|
||||
{
|
||||
return pci_register_driver(&i810_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_i810_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&i810_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Philip Edelbrock <phil@netroedge.com>, "
|
||||
"Ralph Metzler <rjkm@thp.uni-koeln.de>, "
|
||||
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("I810/I815 I2C/DDC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_i810_init);
|
||||
module_exit(i2c_i810_exit);
|
|
@ -42,13 +42,8 @@
|
|||
#include <asm/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
|
||||
#ifdef CONFIG_IBM_OCP
|
||||
#include <asm/ocp.h>
|
||||
#include <asm/ibm4xx.h>
|
||||
#else
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
#include <linux/of_i2c.h>
|
||||
|
||||
#include "i2c-ibm_iic.h"
|
||||
|
||||
|
@ -665,180 +660,6 @@ static inline u8 iic_clckdiv(unsigned int opb)
|
|||
return (u8)((opb + 9) / 10 - 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IBM_OCP
|
||||
/*
|
||||
* Register single IIC interface
|
||||
*/
|
||||
static int __devinit iic_probe(struct ocp_device *ocp){
|
||||
|
||||
struct ibm_iic_private* dev;
|
||||
struct i2c_adapter* adap;
|
||||
struct ocp_func_iic_data* iic_data = ocp->def->additions;
|
||||
int ret;
|
||||
|
||||
if (!iic_data)
|
||||
printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
|
||||
ocp->def->index);
|
||||
|
||||
if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "ibm-iic%d: failed to allocate device data\n",
|
||||
ocp->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->idx = ocp->def->index;
|
||||
ocp_set_drvdata(ocp, dev);
|
||||
|
||||
if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
|
||||
"ibm_iic")) {
|
||||
ret = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
|
||||
printk(KERN_ERR "ibm-iic%d: failed to ioremap device registers\n",
|
||||
dev->idx);
|
||||
ret = -ENXIO;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&dev->wq);
|
||||
|
||||
dev->irq = iic_force_poll ? -1 : ocp->def->irq;
|
||||
if (dev->irq >= 0){
|
||||
/* Disable interrupts until we finish initialization,
|
||||
assumes level-sensitive IRQ setup...
|
||||
*/
|
||||
iic_interrupt_mode(dev, 0);
|
||||
if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
|
||||
printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
|
||||
dev->idx, dev->irq);
|
||||
/* Fallback to the polling mode */
|
||||
dev->irq = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->irq < 0)
|
||||
printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
|
||||
dev->idx);
|
||||
|
||||
/* Board specific settings */
|
||||
dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
|
||||
|
||||
/* clckdiv is the same for *all* IIC interfaces,
|
||||
* but I'd rather make a copy than introduce another global. --ebs
|
||||
*/
|
||||
dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
|
||||
DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
|
||||
|
||||
/* Initialize IIC interface */
|
||||
iic_dev_init(dev);
|
||||
|
||||
/* Register it with i2c layer */
|
||||
adap = &dev->adap;
|
||||
adap->dev.parent = &ocp->dev;
|
||||
strcpy(adap->name, "IBM IIC");
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->id = I2C_HW_OCP;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
adap->algo = &iic_algo;
|
||||
adap->client_register = NULL;
|
||||
adap->client_unregister = NULL;
|
||||
adap->timeout = 1;
|
||||
|
||||
/*
|
||||
* If "dev->idx" 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 = dev->idx >= 0 ? dev->idx : 0;
|
||||
|
||||
if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
|
||||
printk(KERN_ERR "ibm-iic%d: failed to register i2c adapter\n",
|
||||
dev->idx);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
|
||||
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (dev->irq >= 0){
|
||||
iic_interrupt_mode(dev, 0);
|
||||
free_irq(dev->irq, dev);
|
||||
}
|
||||
|
||||
iounmap(dev->vaddr);
|
||||
fail2:
|
||||
release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
|
||||
fail1:
|
||||
ocp_set_drvdata(ocp, NULL);
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup initialized IIC interface
|
||||
*/
|
||||
static void __devexit iic_remove(struct ocp_device *ocp)
|
||||
{
|
||||
struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
|
||||
BUG_ON(dev == NULL);
|
||||
if (i2c_del_adapter(&dev->adap)){
|
||||
printk(KERN_ERR "ibm-iic%d: failed to delete i2c adapter :(\n",
|
||||
dev->idx);
|
||||
/* That's *very* bad, just shutdown IRQ ... */
|
||||
if (dev->irq >= 0){
|
||||
iic_interrupt_mode(dev, 0);
|
||||
free_irq(dev->irq, dev);
|
||||
dev->irq = -1;
|
||||
}
|
||||
} else {
|
||||
if (dev->irq >= 0){
|
||||
iic_interrupt_mode(dev, 0);
|
||||
free_irq(dev->irq, dev);
|
||||
}
|
||||
iounmap(dev->vaddr);
|
||||
release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
|
||||
kfree(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ocp_device_id ibm_iic_ids[] __devinitdata =
|
||||
{
|
||||
{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
|
||||
{ .vendor = OCP_VENDOR_INVALID }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(ocp, ibm_iic_ids);
|
||||
|
||||
static struct ocp_driver ibm_iic_driver =
|
||||
{
|
||||
.name = "iic",
|
||||
.id_table = ibm_iic_ids,
|
||||
.probe = iic_probe,
|
||||
.remove = __devexit_p(iic_remove),
|
||||
#if defined(CONFIG_PM)
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init iic_init(void)
|
||||
{
|
||||
printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
|
||||
return ocp_register_driver(&ibm_iic_driver);
|
||||
}
|
||||
|
||||
static void __exit iic_exit(void)
|
||||
{
|
||||
ocp_unregister_driver(&ibm_iic_driver);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IBM_OCP */
|
||||
|
||||
static int __devinit iic_request_irq(struct of_device *ofdev,
|
||||
struct ibm_iic_private *dev)
|
||||
{
|
||||
|
@ -876,7 +697,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
|
|||
struct device_node *np = ofdev->node;
|
||||
struct ibm_iic_private *dev;
|
||||
struct i2c_adapter *adap;
|
||||
const u32 *indexp, *freq;
|
||||
const u32 *freq;
|
||||
int ret;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
|
@ -887,14 +708,6 @@ static int __devinit iic_probe(struct of_device *ofdev,
|
|||
|
||||
dev_set_drvdata(&ofdev->dev, dev);
|
||||
|
||||
indexp = of_get_property(np, "index", NULL);
|
||||
if (!indexp) {
|
||||
dev_err(&ofdev->dev, "no index specified\n");
|
||||
ret = -EINVAL;
|
||||
goto error_cleanup;
|
||||
}
|
||||
dev->idx = *indexp;
|
||||
|
||||
dev->vaddr = of_iomap(np, 0);
|
||||
if (dev->vaddr == NULL) {
|
||||
dev_err(&ofdev->dev, "failed to iomap device\n");
|
||||
|
@ -934,17 +747,19 @@ static int __devinit iic_probe(struct of_device *ofdev,
|
|||
strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->id = I2C_HW_OCP;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->algo = &iic_algo;
|
||||
adap->timeout = 1;
|
||||
adap->nr = dev->idx;
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
ret = i2c_add_adapter(adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&ofdev->dev, "failed to register i2c adapter\n");
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
/* Now register all the child nodes */
|
||||
of_register_i2c_devices(adap, np);
|
||||
|
||||
dev_info(&ofdev->dev, "using %s mode\n",
|
||||
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
|
||||
|
||||
|
@ -987,11 +802,7 @@ static int __devexit iic_remove(struct of_device *ofdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id ibm_iic_match[] = {
|
||||
{ .compatible = "ibm,iic-405ex", },
|
||||
{ .compatible = "ibm,iic-405gp", },
|
||||
{ .compatible = "ibm,iic-440gp", },
|
||||
{ .compatible = "ibm,iic-440gpx", },
|
||||
{ .compatible = "ibm,iic-440grx", },
|
||||
{ .compatible = "ibm,iic", },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1011,7 +822,6 @@ static void __exit iic_exit(void)
|
|||
{
|
||||
of_unregister_platform_driver(&ibm_iic_driver);
|
||||
}
|
||||
#endif /* CONFIG_IBM_OCP */
|
||||
|
||||
module_init(iic_init);
|
||||
module_exit(iic_exit);
|
||||
|
|
|
@ -482,7 +482,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
|
|||
memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
|
||||
new_adapter->id = I2C_HW_IOP3XX;
|
||||
new_adapter->owner = THIS_MODULE;
|
||||
new_adapter->class = I2C_CLASS_HWMON;
|
||||
new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
new_adapter->dev.parent = &pdev->dev;
|
||||
new_adapter->nr = pdev->id;
|
||||
|
||||
|
|
339
drivers/i2c/busses/i2c-isch.c
Normal file
339
drivers/i2c/busses/i2c-isch.c
Normal file
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
|
||||
- Based on i2c-piix4.c
|
||||
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
- Intel SCH support
|
||||
Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
Supports:
|
||||
Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
/* SCH SMBus address offsets */
|
||||
#define SMBHSTCNT (0 + sch_smba)
|
||||
#define SMBHSTSTS (1 + sch_smba)
|
||||
#define SMBHSTADD (4 + sch_smba) /* TSA */
|
||||
#define SMBHSTCMD (5 + sch_smba)
|
||||
#define SMBHSTDAT0 (6 + sch_smba)
|
||||
#define SMBHSTDAT1 (7 + sch_smba)
|
||||
#define SMBBLKDAT (0x20 + sch_smba)
|
||||
|
||||
/* count for request_region */
|
||||
#define SMBIOSIZE 64
|
||||
|
||||
/* PCI Address Constants */
|
||||
#define SMBBA_SCH 0x40
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_TIMEOUT 500
|
||||
|
||||
/* I2C constants */
|
||||
#define SCH_QUICK 0x00
|
||||
#define SCH_BYTE 0x01
|
||||
#define SCH_BYTE_DATA 0x02
|
||||
#define SCH_WORD_DATA 0x03
|
||||
#define SCH_BLOCK_DATA 0x05
|
||||
|
||||
static unsigned short sch_smba;
|
||||
static struct pci_driver sch_driver;
|
||||
static struct i2c_adapter sch_adapter;
|
||||
|
||||
/*
|
||||
* Start the i2c transaction -- the i2c_access will prepare the transaction
|
||||
* and this function will execute it.
|
||||
* return 0 for success and others for failure.
|
||||
*/
|
||||
static int sch_transaction(void)
|
||||
{
|
||||
int temp;
|
||||
int result = 0;
|
||||
int timeout = 0;
|
||||
|
||||
dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
|
||||
inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
|
||||
inb(SMBHSTDAT1));
|
||||
|
||||
/* Make sure the SMBus host is ready to start transmitting */
|
||||
temp = inb(SMBHSTSTS) & 0x0f;
|
||||
if (temp) {
|
||||
/* Can not be busy since we checked it in sch_access */
|
||||
if (temp & 0x01) {
|
||||
dev_dbg(&sch_adapter.dev, "Completion (%02x). "
|
||||
"Clear...\n", temp);
|
||||
}
|
||||
if (temp & 0x06) {
|
||||
dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
|
||||
"Resetting...\n", temp);
|
||||
}
|
||||
outb(temp, SMBHSTSTS);
|
||||
temp = inb(SMBHSTSTS) & 0x0f;
|
||||
if (temp) {
|
||||
dev_err(&sch_adapter.dev,
|
||||
"SMBus is not ready: (%02x)\n", temp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
/* start the transaction by setting bit 4 */
|
||||
outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
|
||||
|
||||
do {
|
||||
msleep(1);
|
||||
temp = inb(SMBHSTSTS) & 0x0f;
|
||||
} while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
|
||||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
if (temp & 0x04) {
|
||||
result = -EIO;
|
||||
dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
|
||||
"locked until next hard reset. (sorry!)\n");
|
||||
/* Clock stops and slave is stuck in mid-transmission */
|
||||
} else if (temp & 0x02) {
|
||||
result = -EIO;
|
||||
dev_err(&sch_adapter.dev, "Error: no response!\n");
|
||||
} else if (temp & 0x01) {
|
||||
dev_dbg(&sch_adapter.dev, "Post complete!\n");
|
||||
outb(temp, SMBHSTSTS);
|
||||
temp = inb(SMBHSTSTS) & 0x07;
|
||||
if (temp & 0x06) {
|
||||
/* Completion clear failed */
|
||||
dev_dbg(&sch_adapter.dev, "Failed reset at end of "
|
||||
"transaction (%02x), Bus error!\n", temp);
|
||||
}
|
||||
} else {
|
||||
result = -ENXIO;
|
||||
dev_dbg(&sch_adapter.dev, "No such address.\n");
|
||||
}
|
||||
dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
|
||||
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
|
||||
inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
|
||||
inb(SMBHSTDAT1));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main access entry for i2c-sch access
|
||||
* adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
|
||||
* (0 for read and 1 for write), size is i2c transaction type and data is the
|
||||
* union of transaction for data to be transfered or data read from bus.
|
||||
* return 0 for success and others for failure.
|
||||
*/
|
||||
static s32 sch_access(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data *data)
|
||||
{
|
||||
int i, len, temp, rc;
|
||||
|
||||
/* Make sure the SMBus host is not busy */
|
||||
temp = inb(SMBHSTSTS) & 0x0f;
|
||||
if (temp & 0x08) {
|
||||
dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
|
||||
(read_write)?"READ":"WRITE");
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
outb((addr << 1) | read_write, SMBHSTADD);
|
||||
size = SCH_QUICK;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
outb((addr << 1) | read_write, SMBHSTADD);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
outb(command, SMBHSTCMD);
|
||||
size = SCH_BYTE;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
outb((addr << 1) | read_write, SMBHSTADD);
|
||||
outb(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
outb(data->byte, SMBHSTDAT0);
|
||||
size = SCH_BYTE_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
outb((addr << 1) | read_write, SMBHSTADD);
|
||||
outb(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
outb(data->word & 0xff, SMBHSTDAT0);
|
||||
outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
|
||||
}
|
||||
size = SCH_WORD_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
outb((addr << 1) | read_write, SMBHSTADD);
|
||||
outb(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EINVAL;
|
||||
outb(len, SMBHSTDAT0);
|
||||
for (i = 1; i <= len; i++)
|
||||
outb(data->block[i], SMBBLKDAT+i-1);
|
||||
}
|
||||
size = SCH_BLOCK_DATA;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
|
||||
outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
|
||||
|
||||
rc = sch_transaction();
|
||||
if (rc) /* Error in transaction */
|
||||
return rc;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == SCH_QUICK))
|
||||
return 0;
|
||||
|
||||
switch (size) {
|
||||
case SCH_BYTE:
|
||||
case SCH_BYTE_DATA:
|
||||
data->byte = inb(SMBHSTDAT0);
|
||||
break;
|
||||
case SCH_WORD_DATA:
|
||||
data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
|
||||
break;
|
||||
case SCH_BLOCK_DATA:
|
||||
data->block[0] = inb(SMBHSTDAT0);
|
||||
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EPROTO;
|
||||
for (i = 1; i <= data->block[0]; i++)
|
||||
data->block[i] = inb(SMBBLKDAT+i-1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 sch_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = sch_access,
|
||||
.functionality = sch_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter sch_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
static struct pci_device_id sch_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, sch_ids);
|
||||
|
||||
static int __devinit sch_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int retval;
|
||||
unsigned int smba;
|
||||
|
||||
pci_read_config_dword(dev, SMBBA_SCH, &smba);
|
||||
if (!(smba & (1 << 31))) {
|
||||
dev_err(&dev->dev, "SMBus I/O space disabled!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sch_smba = (unsigned short)smba;
|
||||
if (sch_smba == 0) {
|
||||
dev_err(&dev->dev, "SMBus base address uninitialized!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name))
|
||||
return -EBUSY;
|
||||
if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
|
||||
dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
|
||||
sch_smba);
|
||||
return -EBUSY;
|
||||
}
|
||||
dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
sch_adapter.dev.parent = &dev->dev;
|
||||
|
||||
snprintf(sch_adapter.name, sizeof(sch_adapter.name),
|
||||
"SMBus SCH adapter at %04x", sch_smba);
|
||||
|
||||
retval = i2c_add_adapter(&sch_adapter);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "Couldn't register adapter!\n");
|
||||
release_region(sch_smba, SMBIOSIZE);
|
||||
sch_smba = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __devexit sch_remove(struct pci_dev *dev)
|
||||
{
|
||||
if (sch_smba) {
|
||||
i2c_del_adapter(&sch_adapter);
|
||||
release_region(sch_smba, SMBIOSIZE);
|
||||
sch_smba = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct pci_driver sch_driver = {
|
||||
.name = "isch_smbus",
|
||||
.id_table = sch_ids,
|
||||
.probe = sch_probe,
|
||||
.remove = __devexit_p(sch_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_sch_init(void)
|
||||
{
|
||||
return pci_register_driver(&sch_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_sch_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&sch_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel SCH SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_sch_init);
|
||||
module_exit(i2c_sch_exit);
|
|
@ -311,7 +311,7 @@ static struct i2c_adapter mpc_ops = {
|
|||
.name = "MPC adapter",
|
||||
.id = I2C_HW_MPC107,
|
||||
.algo = &mpc_algo,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.timeout = 1,
|
||||
};
|
||||
|
||||
|
|
|
@ -530,7 +530,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
drv_data->adapter.id = I2C_HW_MV64XXX;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON;
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
drv_data->adapter.timeout = pdata->timeout;
|
||||
drv_data->adapter.nr = pd->id;
|
||||
platform_set_drvdata(pd, drv_data);
|
||||
|
|
257
drivers/i2c/busses/i2c-nforce2-s4985.c
Normal file
257
drivers/i2c/busses/i2c-nforce2-s4985.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
|
||||
*
|
||||
* Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We select the channels by sending commands to the Philips
|
||||
* PCA9556 chip at I2C address 0x18. The main adapter is used for
|
||||
* the non-multiplexed part of the bus, and 4 virtual adapters
|
||||
* are defined for the multiplexed addresses: 0x50-0x53 (memory
|
||||
* module EEPROM) located on channels 1-4. We define one virtual
|
||||
* adapter per CPU, which corresponds to one multiplexed channel:
|
||||
* CPU0: virtual adapter 1, channel 1
|
||||
* CPU1: virtual adapter 2, channel 2
|
||||
* CPU2: virtual adapter 3, channel 3
|
||||
* CPU3: virtual adapter 4, channel 4
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
extern struct i2c_adapter *nforce2_smbus;
|
||||
|
||||
static struct i2c_adapter *s4985_adapter;
|
||||
static struct i2c_algorithm *s4985_algo;
|
||||
|
||||
/* Wrapper access functions for multiplexed SMBus */
|
||||
static DEFINE_MUTEX(nforce2_lock);
|
||||
|
||||
static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* We exclude the multiplexed addresses */
|
||||
if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
|
||||
|| addr == 0x18)
|
||||
return -ENXIO;
|
||||
|
||||
mutex_lock(&nforce2_lock);
|
||||
error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
|
||||
command, size, data);
|
||||
mutex_unlock(&nforce2_lock);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* We remember the last used channels combination so as to only switch
|
||||
channels when it is really needed. This greatly reduces the SMBus
|
||||
overhead, but also assumes that nobody will be writing to the PCA9556
|
||||
in our back. */
|
||||
static u8 last_channels;
|
||||
|
||||
static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data,
|
||||
u8 channels)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* We exclude the non-multiplexed addresses */
|
||||
if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
|
||||
return -ENXIO;
|
||||
|
||||
mutex_lock(&nforce2_lock);
|
||||
if (last_channels != channels) {
|
||||
union i2c_smbus_data mplxdata;
|
||||
mplxdata.byte = channels;
|
||||
|
||||
error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
|
||||
I2C_SMBUS_WRITE, 0x01,
|
||||
I2C_SMBUS_BYTE_DATA,
|
||||
&mplxdata);
|
||||
if (error)
|
||||
goto UNLOCK;
|
||||
last_channels = channels;
|
||||
}
|
||||
error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
|
||||
command, size, data);
|
||||
|
||||
UNLOCK:
|
||||
mutex_unlock(&nforce2_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
/* CPU0: channel 1 enabled */
|
||||
return nforce2_access_channel(adap, addr, flags, read_write, command,
|
||||
size, data, 0x02);
|
||||
}
|
||||
|
||||
static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
/* CPU1: channel 2 enabled */
|
||||
return nforce2_access_channel(adap, addr, flags, read_write, command,
|
||||
size, data, 0x04);
|
||||
}
|
||||
|
||||
static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
/* CPU2: channel 3 enabled */
|
||||
return nforce2_access_channel(adap, addr, flags, read_write, command,
|
||||
size, data, 0x08);
|
||||
}
|
||||
|
||||
static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
/* CPU3: channel 4 enabled */
|
||||
return nforce2_access_channel(adap, addr, flags, read_write, command,
|
||||
size, data, 0x10);
|
||||
}
|
||||
|
||||
static int __init nforce2_s4985_init(void)
|
||||
{
|
||||
int i, error;
|
||||
union i2c_smbus_data ioconfig;
|
||||
|
||||
/* Unregister physical bus */
|
||||
if (!nforce2_smbus)
|
||||
return -ENODEV;
|
||||
error = i2c_del_adapter(nforce2_smbus);
|
||||
if (error) {
|
||||
dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n");
|
||||
goto ERROR0;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
|
||||
/* Define the 5 virtual adapters and algorithms structures */
|
||||
s4985_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL);
|
||||
if (!s4985_adapter) {
|
||||
error = -ENOMEM;
|
||||
goto ERROR1;
|
||||
}
|
||||
s4985_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL);
|
||||
if (!s4985_algo) {
|
||||
error = -ENOMEM;
|
||||
goto ERROR2;
|
||||
}
|
||||
|
||||
/* Fill in the new structures */
|
||||
s4985_algo[0] = *(nforce2_smbus->algo);
|
||||
s4985_algo[0].smbus_xfer = nforce2_access_virt0;
|
||||
s4985_adapter[0] = *nforce2_smbus;
|
||||
s4985_adapter[0].algo = s4985_algo;
|
||||
s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
|
||||
for (i = 1; i < 5; i++) {
|
||||
s4985_algo[i] = *(nforce2_smbus->algo);
|
||||
s4985_adapter[i] = *nforce2_smbus;
|
||||
snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
|
||||
"SMBus nForce2 adapter (CPU%d)", i - 1);
|
||||
s4985_adapter[i].algo = s4985_algo + i;
|
||||
s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
|
||||
}
|
||||
s4985_algo[1].smbus_xfer = nforce2_access_virt1;
|
||||
s4985_algo[2].smbus_xfer = nforce2_access_virt2;
|
||||
s4985_algo[3].smbus_xfer = nforce2_access_virt3;
|
||||
s4985_algo[4].smbus_xfer = nforce2_access_virt4;
|
||||
|
||||
/* Configure the PCA9556 multiplexer */
|
||||
ioconfig.byte = 0x00; /* All I/O to output mode */
|
||||
error = nforce2_smbus->algo->smbus_xfer(nforce2_smbus, 0x18, 0,
|
||||
I2C_SMBUS_WRITE, 0x03,
|
||||
I2C_SMBUS_BYTE_DATA, &ioconfig);
|
||||
if (error) {
|
||||
dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
|
||||
error = -EIO;
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
/* Register virtual adapters */
|
||||
for (i = 0; i < 5; i++) {
|
||||
error = i2c_add_adapter(s4985_adapter + i);
|
||||
if (error) {
|
||||
dev_err(&nforce2_smbus->dev,
|
||||
"Virtual adapter %d registration "
|
||||
"failed, module not inserted\n", i);
|
||||
for (i--; i >= 0; i--)
|
||||
i2c_del_adapter(s4985_adapter + i);
|
||||
goto ERROR3;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR3:
|
||||
kfree(s4985_algo);
|
||||
s4985_algo = NULL;
|
||||
ERROR2:
|
||||
kfree(s4985_adapter);
|
||||
s4985_adapter = NULL;
|
||||
ERROR1:
|
||||
/* Restore physical bus */
|
||||
i2c_add_adapter(nforce2_smbus);
|
||||
ERROR0:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit nforce2_s4985_exit(void)
|
||||
{
|
||||
if (s4985_adapter) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
i2c_del_adapter(s4985_adapter+i);
|
||||
kfree(s4985_adapter);
|
||||
s4985_adapter = NULL;
|
||||
}
|
||||
kfree(s4985_algo);
|
||||
s4985_algo = NULL;
|
||||
|
||||
/* Restore physical bus */
|
||||
if (i2c_add_adapter(nforce2_smbus))
|
||||
dev_err(&nforce2_smbus->dev, "Physical bus restoration "
|
||||
"failed\n");
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("S4985 SMBus multiplexing");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(nforce2_s4985_init);
|
||||
module_exit(nforce2_s4985_exit);
|
|
@ -51,6 +51,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -124,6 +125,20 @@ static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {
|
|||
|
||||
static struct pci_driver nforce2_driver;
|
||||
|
||||
/* For multiplexing support, we need a global reference to the 1st
|
||||
SMBus channel */
|
||||
#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
|
||||
struct i2c_adapter *nforce2_smbus;
|
||||
EXPORT_SYMBOL_GPL(nforce2_smbus);
|
||||
|
||||
static void nforce2_set_reference(struct i2c_adapter *adap)
|
||||
{
|
||||
nforce2_smbus = adap;
|
||||
}
|
||||
#else
|
||||
static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
|
||||
#endif
|
||||
|
||||
static void nforce2_abort(struct i2c_adapter *adap)
|
||||
{
|
||||
struct nforce2_smbus *smbus = adap->algo_data;
|
||||
|
@ -158,16 +173,16 @@ static int nforce2_check_status(struct i2c_adapter *adap)
|
|||
dev_dbg(&adap->dev, "SMBus Timeout!\n");
|
||||
if (smbus->can_abort)
|
||||
nforce2_abort(adap);
|
||||
return -1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
|
||||
dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return -1 on error */
|
||||
/* Return negative errno on error */
|
||||
static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
|
@ -175,7 +190,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
|||
struct nforce2_smbus *smbus = adap->algo_data;
|
||||
unsigned char protocol, pec;
|
||||
u8 len;
|
||||
int i;
|
||||
int i, status;
|
||||
|
||||
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
|
||||
NVIDIA_SMB_PRTCL_WRITE;
|
||||
|
@ -219,7 +234,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
|||
"Transaction failed "
|
||||
"(requested block size: %d)\n",
|
||||
len);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
outb_p(len, NVIDIA_SMB_BCNT);
|
||||
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
|
||||
|
@ -231,14 +246,15 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
|||
|
||||
default:
|
||||
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
|
||||
outb_p(protocol, NVIDIA_SMB_PRTCL);
|
||||
|
||||
if (nforce2_check_status(adap))
|
||||
return -1;
|
||||
status = nforce2_check_status(adap);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
return 0;
|
||||
|
@ -260,7 +276,7 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
|
|||
dev_err(&adap->dev, "Transaction failed "
|
||||
"(received block size: 0x%02x)\n",
|
||||
len);
|
||||
return -1;
|
||||
return -EPROTO;
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
|
||||
|
@ -321,21 +337,26 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
|
|||
!= PCIBIOS_SUCCESSFUL) {
|
||||
dev_err(&dev->dev, "Error reading PCI config for %s\n",
|
||||
name);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
|
||||
smbus->size = 64;
|
||||
}
|
||||
|
||||
error = acpi_check_region(smbus->base, smbus->size,
|
||||
nforce2_driver.name);
|
||||
if (error)
|
||||
return -1;
|
||||
|
||||
if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
|
||||
dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
|
||||
smbus->base, smbus->base+smbus->size-1, name);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
}
|
||||
smbus->adapter.owner = THIS_MODULE;
|
||||
smbus->adapter.id = I2C_HW_SMBUS_NFORCE2;
|
||||
smbus->adapter.class = I2C_CLASS_HWMON;
|
||||
smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
smbus->adapter.algo = &smbus_algorithm;
|
||||
smbus->adapter.algo_data = smbus;
|
||||
smbus->adapter.dev.parent = &dev->dev;
|
||||
|
@ -346,7 +367,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
|
|||
if (error) {
|
||||
dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
|
||||
release_region(smbus->base, smbus->size);
|
||||
return -1;
|
||||
return error;
|
||||
}
|
||||
dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);
|
||||
return 0;
|
||||
|
@ -398,6 +419,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
nforce2_set_reference(&smbuses[0].adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -406,6 +428,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev)
|
|||
{
|
||||
struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
|
||||
|
||||
nforce2_set_reference(NULL);
|
||||
if (smbuses[0].base) {
|
||||
i2c_del_adapter(&smbuses[0].adapter);
|
||||
release_region(smbuses[0].base, smbuses[0].size);
|
||||
|
|
|
@ -29,6 +29,7 @@ struct ocores_i2c {
|
|||
int pos;
|
||||
int nmsgs;
|
||||
int state; /* see STATE_ */
|
||||
int clock_khz;
|
||||
};
|
||||
|
||||
/* registers */
|
||||
|
@ -173,8 +174,7 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void ocores_init(struct ocores_i2c *i2c,
|
||||
struct ocores_i2c_platform_data *pdata)
|
||||
static void ocores_init(struct ocores_i2c *i2c)
|
||||
{
|
||||
int prescale;
|
||||
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
|
||||
|
@ -182,7 +182,7 @@ static void ocores_init(struct ocores_i2c *i2c,
|
|||
/* make sure the device is disabled */
|
||||
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
|
||||
|
||||
prescale = (pdata->clock_khz / (5*100)) - 1;
|
||||
prescale = (i2c->clock_khz / (5*100)) - 1;
|
||||
oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
|
||||
oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
|
||||
|
||||
|
@ -205,7 +205,7 @@ static const struct i2c_algorithm ocores_algorithm = {
|
|||
static struct i2c_adapter ocores_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-ocores",
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &ocores_algorithm,
|
||||
};
|
||||
|
||||
|
@ -248,7 +248,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
i2c->regstep = pdata->regstep;
|
||||
ocores_init(i2c, pdata);
|
||||
i2c->clock_khz = pdata->clock_khz;
|
||||
ocores_init(i2c);
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c);
|
||||
|
@ -312,13 +313,40 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
|
||||
|
||||
/* make sure the device is disabled */
|
||||
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocores_i2c_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
ocores_init(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ocores_i2c_suspend NULL
|
||||
#define ocores_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:ocores-i2c");
|
||||
|
||||
static struct platform_driver ocores_i2c_driver = {
|
||||
.probe = ocores_i2c_probe,
|
||||
.remove = __devexit_p(ocores_i2c_remove),
|
||||
.driver = {
|
||||
.probe = ocores_i2c_probe,
|
||||
.remove = __devexit_p(ocores_i2c_remove),
|
||||
.suspend = ocores_i2c_suspend,
|
||||
.resume = ocores_i2c_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ocores-i2c",
|
||||
},
|
||||
|
|
|
@ -365,7 +365,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
|
|||
smbus->adapter.owner = THIS_MODULE;
|
||||
snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
|
||||
"PA Semi SMBus adapter at 0x%lx", smbus->base);
|
||||
smbus->adapter.class = I2C_CLASS_HWMON;
|
||||
smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
smbus->adapter.algo = &smbus_algorithm;
|
||||
smbus->adapter.algo_data = smbus;
|
||||
smbus->adapter.nr = PCI_FUNC(dev->devfn);
|
||||
|
|
|
@ -163,7 +163,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
|
|||
|
||||
i2c->reg_base = ioremap(res->start, res_len(res));
|
||||
if (!i2c->reg_base) {
|
||||
ret = -EIO;
|
||||
ret = -ENOMEM;
|
||||
goto e_remap;
|
||||
}
|
||||
i2c->io_base = res->start;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
piix4.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
|
@ -39,16 +37,10 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
struct sd {
|
||||
const unsigned short mfr;
|
||||
const unsigned short dev;
|
||||
const unsigned char fn;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* PIIX4 SMBus address offsets */
|
||||
#define SMBHSTSTS (0 + piix4_smba)
|
||||
#define SMBHSLVSTS (1 + piix4_smba)
|
||||
|
@ -101,8 +93,6 @@ MODULE_PARM_DESC(force_addr,
|
|||
"Forcibly enable the PIIX4 at the given address. "
|
||||
"EXTREMELY DANGEROUS!");
|
||||
|
||||
static int piix4_transaction(void);
|
||||
|
||||
static unsigned short piix4_smba;
|
||||
static int srvrworks_csb5_delay;
|
||||
static struct pci_driver piix4_driver;
|
||||
|
@ -141,8 +131,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
|||
{
|
||||
unsigned char temp;
|
||||
|
||||
dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
|
||||
|
||||
if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
|
||||
(PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
|
||||
srvrworks_csb5_delay = 1;
|
||||
|
@ -172,17 +160,20 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
|||
pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
|
||||
piix4_smba &= 0xfff0;
|
||||
if(piix4_smba == 0) {
|
||||
dev_err(&PIIX4_dev->dev, "SMB base address "
|
||||
dev_err(&PIIX4_dev->dev, "SMBus base address "
|
||||
"uninitialized - upgrade BIOS or use "
|
||||
"force_addr=0xaddr\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
|
||||
return -EBUSY;
|
||||
|
||||
if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
|
||||
dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n",
|
||||
dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
|
||||
piix4_smba);
|
||||
return -ENODEV;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
|
||||
|
@ -228,13 +219,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
|
|||
"(or code out of date)!\n");
|
||||
|
||||
pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
|
||||
dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp);
|
||||
dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba);
|
||||
dev_info(&PIIX4_dev->dev,
|
||||
"SMBus Host Controller at 0x%x, revision %d\n",
|
||||
piix4_smba, temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Another internally used function */
|
||||
static int piix4_transaction(void)
|
||||
{
|
||||
int temp;
|
||||
|
@ -253,7 +244,7 @@ static int piix4_transaction(void)
|
|||
outb_p(temp, SMBHSTSTS);
|
||||
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
|
||||
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dev_dbg(&piix4_adapter.dev, "Successful!\n");
|
||||
}
|
||||
|
@ -275,23 +266,23 @@ static int piix4_transaction(void)
|
|||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
|
||||
}
|
||||
|
||||
if (temp & 0x08) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_dbg(&piix4_adapter.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) {
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
|
||||
}
|
||||
|
||||
|
@ -309,31 +300,29 @@ static int piix4_transaction(void)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
int i, len;
|
||||
int status;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
|
||||
return -1;
|
||||
case I2C_SMBUS_QUICK:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
size = PIIX4_QUICK;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
outb_p(command, SMBHSTCMD);
|
||||
size = PIIX4_BYTE;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
|
@ -341,7 +330,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
size = PIIX4_BYTE_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
|
@ -351,15 +340,13 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
size = PIIX4_WORD_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTCMD);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
if (len > 32)
|
||||
len = 32;
|
||||
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EINVAL;
|
||||
outb_p(len, SMBHSTDAT0);
|
||||
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
for (i = 1; i <= len; i++)
|
||||
|
@ -367,12 +354,16 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
}
|
||||
size = PIIX4_BLOCK_DATA;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
|
||||
|
||||
if (piix4_transaction()) /* Error in transaction */
|
||||
return -1;
|
||||
status = piix4_transaction();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
|
||||
return 0;
|
||||
|
@ -388,6 +379,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
break;
|
||||
case PIIX4_BLOCK_DATA:
|
||||
data->block[0] = inb_p(SMBHSTDAT0);
|
||||
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EPROTO;
|
||||
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
for (i = 1; i <= data->block[0]; i++)
|
||||
data->block[i] = inb_p(SMBBLKDAT);
|
||||
|
@ -411,7 +404,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter piix4_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_PIIX4,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -622,7 +622,7 @@ static struct i2c_algorithm pmcmsptwi_algo = {
|
|||
|
||||
static struct i2c_adapter pmcmsptwi_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &pmcmsptwi_algo,
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
|
|
@ -1,325 +0,0 @@
|
|||
/*
|
||||
* kernel/busses/i2c-prosavage.c
|
||||
*
|
||||
* i2c bus driver for S3/VIA 8365/8375 graphics processor.
|
||||
* Copyright (c) 2003 Henk Vergonet <henk@god.dyndns.org>
|
||||
* Based on code written by:
|
||||
* Frodo Looijaard <frodol@dds.nl>,
|
||||
* Philip Edelbrock <phil@netroedge.com>,
|
||||
* Ralph Metzler <rjkm@thp.uni-koeln.de>, and
|
||||
* Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
* Simon Vogl
|
||||
* and others
|
||||
*
|
||||
* Please read the lm_sensors documentation for details on use.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
/* 18-05-2003 HVE - created
|
||||
* 14-06-2003 HVE - adapted for lm_sensors2
|
||||
* 17-06-2003 HVE - linux 2.5.xx compatible
|
||||
* 18-06-2003 HVE - codingstyle
|
||||
* 21-06-2003 HVE - compatibility lm_sensors2 and linux 2.5.xx
|
||||
* codingstyle, mmio enabled
|
||||
*
|
||||
* This driver interfaces to the I2C bus of the VIA north bridge embedded
|
||||
* ProSavage4/8 devices. Usefull for gaining access to the TV Encoder chips.
|
||||
*
|
||||
* Graphics cores:
|
||||
* S3/VIA KM266/VT8375 aka ProSavage8
|
||||
* S3/VIA KM133/VT8365 aka Savage4
|
||||
*
|
||||
* Two serial busses are implemented:
|
||||
* SERIAL1 - I2C serial communications interface
|
||||
* SERIAL2 - DDC2 monitor communications interface
|
||||
*
|
||||
* Tested on a FX41 mainboard, see http://www.shuttle.com
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
* - integration with prosavage framebuffer device
|
||||
* (Additional documentation needed :(
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* driver configuration
|
||||
*/
|
||||
#define MAX_BUSSES 2
|
||||
|
||||
struct s_i2c_bus {
|
||||
void __iomem *mmvga;
|
||||
int i2c_reg;
|
||||
int adap_ok;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_bit_data algo;
|
||||
};
|
||||
|
||||
struct s_i2c_chip {
|
||||
void __iomem *mmio;
|
||||
struct s_i2c_bus i2c_bus[MAX_BUSSES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* i2c configuration
|
||||
*/
|
||||
#define CYCLE_DELAY 10
|
||||
#define TIMEOUT (HZ / 2)
|
||||
|
||||
|
||||
/*
|
||||
* S3/VIA 8365/8375 registers
|
||||
*/
|
||||
#define VGA_CR_IX 0x3d4
|
||||
#define VGA_CR_DATA 0x3d5
|
||||
|
||||
#define CR_SERIAL1 0xa0 /* I2C serial communications interface */
|
||||
#define MM_SERIAL1 0xff20
|
||||
#define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */
|
||||
|
||||
/* based on vt8365 documentation */
|
||||
#define I2C_ENAB 0x10
|
||||
#define I2C_SCL_OUT 0x01
|
||||
#define I2C_SDA_OUT 0x02
|
||||
#define I2C_SCL_IN 0x04
|
||||
#define I2C_SDA_IN 0x08
|
||||
|
||||
#define SET_CR_IX(p, val) writeb((val), (p)->mmvga + VGA_CR_IX)
|
||||
#define SET_CR_DATA(p, val) writeb((val), (p)->mmvga + VGA_CR_DATA)
|
||||
#define GET_CR_DATA(p) readb((p)->mmvga + VGA_CR_DATA)
|
||||
|
||||
|
||||
/*
|
||||
* Serial bus line handling
|
||||
*
|
||||
* serial communications register as parameter in private data
|
||||
*
|
||||
* TODO: locks with other code sections accessing video registers?
|
||||
*/
|
||||
static void bit_s3via_setscl(void *bus, int val)
|
||||
{
|
||||
struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
|
||||
unsigned int r;
|
||||
|
||||
SET_CR_IX(p, p->i2c_reg);
|
||||
r = GET_CR_DATA(p);
|
||||
r |= I2C_ENAB;
|
||||
if (val) {
|
||||
r |= I2C_SCL_OUT;
|
||||
} else {
|
||||
r &= ~I2C_SCL_OUT;
|
||||
}
|
||||
SET_CR_DATA(p, r);
|
||||
}
|
||||
|
||||
static void bit_s3via_setsda(void *bus, int val)
|
||||
{
|
||||
struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
|
||||
unsigned int r;
|
||||
|
||||
SET_CR_IX(p, p->i2c_reg);
|
||||
r = GET_CR_DATA(p);
|
||||
r |= I2C_ENAB;
|
||||
if (val) {
|
||||
r |= I2C_SDA_OUT;
|
||||
} else {
|
||||
r &= ~I2C_SDA_OUT;
|
||||
}
|
||||
SET_CR_DATA(p, r);
|
||||
}
|
||||
|
||||
static int bit_s3via_getscl(void *bus)
|
||||
{
|
||||
struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
|
||||
|
||||
SET_CR_IX(p, p->i2c_reg);
|
||||
return (0 != (GET_CR_DATA(p) & I2C_SCL_IN));
|
||||
}
|
||||
|
||||
static int bit_s3via_getsda(void *bus)
|
||||
{
|
||||
struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
|
||||
|
||||
SET_CR_IX(p, p->i2c_reg);
|
||||
return (0 != (GET_CR_DATA(p) & I2C_SDA_IN));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* adapter initialisation
|
||||
*/
|
||||
static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg)
|
||||
{
|
||||
int ret;
|
||||
p->adap.owner = THIS_MODULE;
|
||||
p->adap.id = I2C_HW_B_S3VIA;
|
||||
p->adap.algo_data = &p->algo;
|
||||
p->adap.dev.parent = &dev->dev;
|
||||
p->algo.setsda = bit_s3via_setsda;
|
||||
p->algo.setscl = bit_s3via_setscl;
|
||||
p->algo.getsda = bit_s3via_getsda;
|
||||
p->algo.getscl = bit_s3via_getscl;
|
||||
p->algo.udelay = CYCLE_DELAY;
|
||||
p->algo.timeout = TIMEOUT;
|
||||
p->algo.data = p;
|
||||
p->mmvga = mmvga;
|
||||
p->i2c_reg = i2c_reg;
|
||||
|
||||
ret = i2c_bit_add_bus(&p->adap);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
p->adap_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cleanup stuff
|
||||
*/
|
||||
static void prosavage_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct s_i2c_chip *chip;
|
||||
int i, ret;
|
||||
|
||||
chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
|
||||
|
||||
if (!chip) {
|
||||
return;
|
||||
}
|
||||
for (i = MAX_BUSSES - 1; i >= 0; i--) {
|
||||
if (chip->i2c_bus[i].adap_ok == 0)
|
||||
continue;
|
||||
|
||||
ret = i2c_del_adapter(&chip->i2c_bus[i].adap);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "%s not removed\n",
|
||||
chip->i2c_bus[i].adap.name);
|
||||
}
|
||||
}
|
||||
if (chip->mmio) {
|
||||
iounmap(chip->mmio);
|
||||
}
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Detect chip and initialize it
|
||||
*/
|
||||
static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
unsigned long base, len;
|
||||
struct s_i2c_chip *chip;
|
||||
struct s_i2c_bus *bus;
|
||||
|
||||
pci_set_drvdata(dev, kzalloc(sizeof(struct s_i2c_chip), GFP_KERNEL));
|
||||
chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
|
||||
if (chip == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
len = dev->resource[0].end - base + 1;
|
||||
chip->mmio = ioremap_nocache(base, len);
|
||||
|
||||
if (chip->mmio == NULL) {
|
||||
dev_err(&dev->dev, "ioremap failed\n");
|
||||
prosavage_remove(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Chip initialisation
|
||||
*/
|
||||
/* Unlock Extended IO Space ??? */
|
||||
|
||||
|
||||
/*
|
||||
* i2c bus registration
|
||||
*/
|
||||
bus = &chip->i2c_bus[0];
|
||||
snprintf(bus->adap.name, sizeof(bus->adap.name),
|
||||
"ProSavage I2C bus at %02x:%02x.%x",
|
||||
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||
ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL1);
|
||||
if (ret) {
|
||||
goto err_adap;
|
||||
}
|
||||
/*
|
||||
* ddc bus registration
|
||||
*/
|
||||
bus = &chip->i2c_bus[1];
|
||||
snprintf(bus->adap.name, sizeof(bus->adap.name),
|
||||
"ProSavage DDC bus at %02x:%02x.%x",
|
||||
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||
ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL2);
|
||||
if (ret) {
|
||||
goto err_adap;
|
||||
}
|
||||
return 0;
|
||||
err_adap:
|
||||
dev_err(&dev->dev, "%s failed\n", bus->adap.name);
|
||||
prosavage_remove(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Data for PCI driver interface
|
||||
*/
|
||||
static struct pci_device_id prosavage_pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SAVAGE4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_PROSAVAGE8) },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
|
||||
|
||||
static struct pci_driver prosavage_driver = {
|
||||
.name = "prosavage_smbus",
|
||||
.id_table = prosavage_pci_tbl,
|
||||
.probe = prosavage_probe,
|
||||
.remove = prosavage_remove,
|
||||
};
|
||||
|
||||
static int __init i2c_prosavage_init(void)
|
||||
{
|
||||
return pci_register_driver(&prosavage_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_prosavage_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&prosavage_driver);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, prosavage_pci_tbl);
|
||||
MODULE_AUTHOR("Henk Vergonet");
|
||||
MODULE_DESCRIPTION("ProSavage VIA 8365/8375 smbus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init (i2c_prosavage_init);
|
||||
module_exit (i2c_prosavage_exit);
|
|
@ -1104,5 +1104,5 @@ static void __exit i2c_adap_pxa_exit(void)
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pxa2xx-i2c");
|
||||
|
||||
module_init(i2c_adap_pxa_init);
|
||||
subsys_initcall(i2c_adap_pxa_init);
|
||||
module_exit(i2c_adap_pxa_exit);
|
||||
|
|
|
@ -590,7 +590,7 @@ static struct s3c24xx_i2c s3c24xx_i2c = {
|
|||
.owner = THIS_MODULE,
|
||||
.algo = &s3c24xx_i2c_algorithm,
|
||||
.retries = 2,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
i2c-savage4.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (C) 1998-2003 The LM Sensors Team
|
||||
Alexander Wold <awold@bigfoot.com>
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Based on i2c-voodoo3.c.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* This interfaces to the I2C bus of the Savage4 to gain access to
|
||||
the BT869 and possibly other I2C devices. The DDC bus is not
|
||||
yet supported because its register is not memory-mapped.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* device IDs */
|
||||
#define PCI_CHIP_SAVAGE4 0x8A22
|
||||
#define PCI_CHIP_SAVAGE2000 0x9102
|
||||
|
||||
#define REG 0xff20 /* Serial Port 1 Register */
|
||||
|
||||
/* bit locations in the register */
|
||||
#define I2C_ENAB 0x00000020
|
||||
#define I2C_SCL_OUT 0x00000001
|
||||
#define I2C_SDA_OUT 0x00000002
|
||||
#define I2C_SCL_IN 0x00000008
|
||||
#define I2C_SDA_IN 0x00000010
|
||||
|
||||
/* delays */
|
||||
#define CYCLE_DELAY 10
|
||||
#define TIMEOUT (HZ / 2)
|
||||
|
||||
|
||||
static void __iomem *ioaddr;
|
||||
|
||||
/* The sav GPIO registers don't have individual masks for each bit
|
||||
so we always have to read before writing. */
|
||||
|
||||
static void bit_savi2c_setscl(void *data, int val)
|
||||
{
|
||||
unsigned int r;
|
||||
r = readl(ioaddr + REG);
|
||||
if(val)
|
||||
r |= I2C_SCL_OUT;
|
||||
else
|
||||
r &= ~I2C_SCL_OUT;
|
||||
writel(r, ioaddr + REG);
|
||||
readl(ioaddr + REG); /* flush posted write */
|
||||
}
|
||||
|
||||
static void bit_savi2c_setsda(void *data, int val)
|
||||
{
|
||||
unsigned int r;
|
||||
r = readl(ioaddr + REG);
|
||||
if(val)
|
||||
r |= I2C_SDA_OUT;
|
||||
else
|
||||
r &= ~I2C_SDA_OUT;
|
||||
writel(r, ioaddr + REG);
|
||||
readl(ioaddr + REG); /* flush posted write */
|
||||
}
|
||||
|
||||
/* The GPIO pins are open drain, so the pins always remain outputs.
|
||||
We rely on the i2c-algo-bit routines to set the pins high before
|
||||
reading the input from other chips. */
|
||||
|
||||
static int bit_savi2c_getscl(void *data)
|
||||
{
|
||||
return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
|
||||
}
|
||||
|
||||
static int bit_savi2c_getsda(void *data)
|
||||
{
|
||||
return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
|
||||
}
|
||||
|
||||
/* Configures the chip */
|
||||
|
||||
static int config_s4(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long cadr;
|
||||
|
||||
/* map memory */
|
||||
cadr = dev->resource[0].start;
|
||||
cadr &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
ioaddr = ioremap_nocache(cadr, 0x0080000);
|
||||
if (ioaddr) {
|
||||
/* writel(0x8160, ioaddr + REG2); */
|
||||
writel(0x00000020, ioaddr + REG);
|
||||
dev_info(&dev->dev, "Using Savage4 at %p\n", ioaddr);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct i2c_algo_bit_data sav_i2c_bit_data = {
|
||||
.setsda = bit_savi2c_setsda,
|
||||
.setscl = bit_savi2c_setscl,
|
||||
.getsda = bit_savi2c_getsda,
|
||||
.getscl = bit_savi2c_getscl,
|
||||
.udelay = CYCLE_DELAY,
|
||||
.timeout = TIMEOUT
|
||||
};
|
||||
|
||||
static struct i2c_adapter savage4_i2c_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_B_SAVAGE,
|
||||
.name = "I2C Savage4 adapter",
|
||||
.algo_data = &sav_i2c_bit_data,
|
||||
};
|
||||
|
||||
static struct pci_device_id savage4_ids[] __devinitdata = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (pci, savage4_ids);
|
||||
|
||||
static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = config_s4(dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
savage4_i2c_adapter.dev.parent = &dev->dev;
|
||||
|
||||
return i2c_bit_add_bus(&savage4_i2c_adapter);
|
||||
}
|
||||
|
||||
static void __devexit savage4_remove(struct pci_dev *dev)
|
||||
{
|
||||
i2c_del_adapter(&savage4_i2c_adapter);
|
||||
iounmap(ioaddr);
|
||||
}
|
||||
|
||||
static struct pci_driver savage4_driver = {
|
||||
.name = "savage4_smbus",
|
||||
.id_table = savage4_ids,
|
||||
.probe = savage4_probe,
|
||||
.remove = __devexit_p(savage4_remove),
|
||||
};
|
||||
|
||||
static int __init i2c_savage4_init(void)
|
||||
{
|
||||
return pci_register_driver(&savage4_driver);
|
||||
}
|
||||
|
||||
static void __exit i2c_savage4_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&savage4_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Alexander Wold <awold@bigfoot.com> "
|
||||
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("Savage4 I2C/SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_savage4_init);
|
||||
module_exit(i2c_savage4_exit);
|
|
@ -143,7 +143,7 @@ static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
|
|||
csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
|
||||
csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
|
||||
|
||||
return i2c_add_adapter(i2c_adap);
|
||||
return i2c_add_numbered_adapter(i2c_adap);
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,17 +156,19 @@ static struct i2c_adapter sibyte_board_adapter[2] = {
|
|||
{
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SIBYTE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = NULL,
|
||||
.algo_data = &sibyte_board_data[0],
|
||||
.nr = 0,
|
||||
.name = "SiByte SMBus 0",
|
||||
},
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SIBYTE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = NULL,
|
||||
.algo_data = &sibyte_board_data[1],
|
||||
.nr = 1,
|
||||
.name = "SiByte SMBus 1",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
sis5595.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
|
@ -62,6 +60,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static int blacklist[] = {
|
||||
|
@ -174,6 +173,11 @@ static int sis5595_setup(struct pci_dev *SIS5595_dev)
|
|||
|
||||
/* NB: We grab just the two SMBus registers here, but this may still
|
||||
* interfere with ACPI :-( */
|
||||
retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
|
||||
sis5595_driver.name);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!request_region(sis5595_base + SMB_INDEX, 2,
|
||||
sis5595_driver.name)) {
|
||||
dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
|
||||
|
@ -236,7 +240,7 @@ static int sis5595_transaction(struct i2c_adapter *adap)
|
|||
sis5595_write(SMB_STS_HI, temp >> 8);
|
||||
if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
|
||||
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "Successful!\n");
|
||||
}
|
||||
|
@ -254,19 +258,19 @@ static int sis5595_transaction(struct i2c_adapter *adap)
|
|||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&adap->dev, "SMBus Timeout!\n");
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
}
|
||||
|
||||
if (temp & 0x20) {
|
||||
dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
|
||||
"next hard reset (or not...)\n");
|
||||
/* Clock stops and slave is stuck in mid-transmission */
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
|
||||
|
@ -282,11 +286,13 @@ static int sis5595_transaction(struct i2c_adapter *adap)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data *data)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
|
||||
|
@ -318,13 +324,14 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
|
|||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
|
||||
|
||||
if (sis5595_transaction(adap))
|
||||
return -1;
|
||||
status = sis5595_transaction(adap);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((size != SIS5595_PROC_CALL) &&
|
||||
((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
|
||||
|
@ -359,7 +366,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter sis5595_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_SIS5595,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
i2c-sis630.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -55,6 +52,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* SIS630 SMBus registers */
|
||||
|
@ -134,7 +132,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc
|
|||
|
||||
if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
|
||||
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "Successful!\n");
|
||||
}
|
||||
|
@ -177,17 +175,17 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
|
|||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&adap->dev, "SMBus Timeout!\n");
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (temp & 0x02) {
|
||||
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
}
|
||||
|
||||
if (temp & 0x04) {
|
||||
dev_err(&adap->dev, "Bus collision!\n");
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
/*
|
||||
TBD: Datasheet say:
|
||||
the software should clear this bit and restart SMBUS operation.
|
||||
|
@ -250,8 +248,10 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat
|
|||
if (i==8 || (len<8 && i==len)) {
|
||||
dev_dbg(&adap->dev, "start trans len=%d i=%d\n",len ,i);
|
||||
/* first transaction */
|
||||
if (sis630_transaction_start(adap, SIS630_BLOCK_DATA, &oldclock))
|
||||
return -1;
|
||||
rc = sis630_transaction_start(adap,
|
||||
SIS630_BLOCK_DATA, &oldclock);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
else if ((i-1)%8 == 7 || i==len) {
|
||||
dev_dbg(&adap->dev, "trans_wait len=%d i=%d\n",len,i);
|
||||
|
@ -264,9 +264,10 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat
|
|||
*/
|
||||
sis630_write(SMB_STS,0x10);
|
||||
}
|
||||
if (sis630_transaction_wait(adap, SIS630_BLOCK_DATA)) {
|
||||
rc = sis630_transaction_wait(adap,
|
||||
SIS630_BLOCK_DATA);
|
||||
if (rc) {
|
||||
dev_dbg(&adap->dev, "trans_wait failed\n");
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -275,13 +276,14 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat
|
|||
else {
|
||||
/* read request */
|
||||
data->block[0] = len = 0;
|
||||
if (sis630_transaction_start(adap, SIS630_BLOCK_DATA, &oldclock)) {
|
||||
return -1;
|
||||
}
|
||||
rc = sis630_transaction_start(adap,
|
||||
SIS630_BLOCK_DATA, &oldclock);
|
||||
if (rc)
|
||||
return rc;
|
||||
do {
|
||||
if (sis630_transaction_wait(adap, SIS630_BLOCK_DATA)) {
|
||||
rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
|
||||
if (rc) {
|
||||
dev_dbg(&adap->dev, "trans_wait failed\n");
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
/* if this first transaction then read byte count */
|
||||
|
@ -311,11 +313,13 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data *data)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
|
||||
|
@ -350,13 +354,14 @@ static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
|
|||
size = SIS630_BLOCK_DATA;
|
||||
return sis630_block_data(adap, data, read_write);
|
||||
default:
|
||||
printk("Unsupported I2C size\n");
|
||||
return -1;
|
||||
break;
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n",
|
||||
size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (sis630_transaction(adap, size))
|
||||
return -1;
|
||||
status = sis630_transaction(adap, size);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((size != SIS630_PCALL) &&
|
||||
((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
|
||||
|
@ -372,9 +377,6 @@ static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
|
|||
case SIS630_WORD_DATA:
|
||||
data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -433,6 +435,11 @@ static int sis630_setup(struct pci_dev *sis630_dev)
|
|||
|
||||
dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
|
||||
|
||||
retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
|
||||
sis630_driver.name);
|
||||
if (retval)
|
||||
goto exit;
|
||||
|
||||
/* Everything is happy, let's grab the memory and set things up. */
|
||||
if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
|
||||
sis630_driver.name)) {
|
||||
|
@ -458,7 +465,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter sis630_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_SIS630,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
sis96x.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -40,6 +37,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* base address register in PCI config space */
|
||||
|
@ -111,7 +109,7 @@ static int sis96x_transaction(int size)
|
|||
/* check it again */
|
||||
if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
|
||||
dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dev_dbg(&sis96x_adapter.dev, "Successful\n");
|
||||
}
|
||||
|
@ -136,19 +134,19 @@ static int sis96x_transaction(int size)
|
|||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* device error - probably missing ACK */
|
||||
if (temp & 0x02) {
|
||||
dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
}
|
||||
|
||||
/* bus collision */
|
||||
if (temp & 0x04) {
|
||||
dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
/* Finish up by resetting the bus */
|
||||
|
@ -161,11 +159,12 @@ static int sis96x_transaction(int size)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
|
@ -200,20 +199,14 @@ static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
|
|||
SIS96x_PROC_CALL : SIS96x_WORD_DATA);
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
/* TO DO: */
|
||||
dev_info(&adap->dev, "SMBus block not implemented!\n");
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(&adap->dev, "Unsupported I2C size\n");
|
||||
return -1;
|
||||
break;
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (sis96x_transaction(size))
|
||||
return -1;
|
||||
status = sis96x_transaction(size);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((size != SIS96x_PROC_CALL) &&
|
||||
((read_write == I2C_SMBUS_WRITE) || (size == SIS96x_QUICK)))
|
||||
|
@ -249,7 +242,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter sis96x_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_SIS96X,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
@ -286,6 +279,10 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
|
|||
dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
|
||||
sis96x_smbus_base);
|
||||
|
||||
retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Everything is happy, let's grab the memory and set things up. */
|
||||
if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
|
||||
sis96x_driver.name)) {
|
||||
|
|
|
@ -43,7 +43,7 @@ struct stub_chip {
|
|||
|
||||
static struct stub_chip *stub_chips;
|
||||
|
||||
/* Return -1 on error. */
|
||||
/* Return negative errno on error. */
|
||||
static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
||||
char read_write, u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
|
@ -120,7 +120,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
|||
|
||||
default:
|
||||
dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
|
||||
ret = -1;
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
} /* switch (size) */
|
||||
|
||||
|
@ -140,7 +140,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
|
||||
static struct i2c_adapter stub_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
.name = "SMBus stub driver",
|
||||
};
|
||||
|
|
|
@ -96,9 +96,8 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|||
sprintf(p, "$%02X", command);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(&adapter->dev, "Unsupported transaction size %d\n",
|
||||
size);
|
||||
return -EINVAL;
|
||||
dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Send the transaction to the TAOS EVM */
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/*
|
||||
i2c-via.c - Part of lm_sensors, Linux kernel modules
|
||||
for hardware monitoring
|
||||
|
||||
i2c Support for Via Technologies 82C586B South Bridge
|
||||
|
||||
Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
|
@ -87,7 +84,7 @@ static struct i2c_algo_bit_data bit_data = {
|
|||
static struct i2c_adapter vt586b_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_B_VIA,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.name = "VIA i2c",
|
||||
.algo_data = &bit_data,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
@ -50,6 +48,7 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static struct pci_dev *vt596_pdev;
|
||||
|
@ -152,7 +151,7 @@ static int vt596_transaction(u8 size)
|
|||
if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
|
||||
dev_err(&vt596_adapter.dev, "SMBus reset failed! "
|
||||
"(0x%02x)\n", temp);
|
||||
return -1;
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,24 +166,24 @@ static int vt596_transaction(u8 size)
|
|||
|
||||
/* If the SMBus is still busy, we give up */
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
result = -1;
|
||||
result = -ETIMEDOUT;
|
||||
dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
|
||||
}
|
||||
|
||||
if (temp & 0x10) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
|
||||
size);
|
||||
}
|
||||
|
||||
if (temp & 0x08) {
|
||||
result = -1;
|
||||
result = -EIO;
|
||||
dev_err(&vt596_adapter.dev, "SMBus collision!\n");
|
||||
}
|
||||
|
||||
if (temp & 0x04) {
|
||||
int read = inb_p(SMBHSTADD) & 0x01;
|
||||
result = -1;
|
||||
result = -ENXIO;
|
||||
/* The quick and receive byte commands are used to probe
|
||||
for chips, so errors are expected, and we don't want
|
||||
to frighten the user. */
|
||||
|
@ -202,12 +201,13 @@ static int vt596_transaction(u8 size)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Return -1 on error, 0 on success */
|
||||
/* Return negative errno on error, 0 on success */
|
||||
static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write, u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
int i;
|
||||
int status;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
|
@ -258,8 +258,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
|||
|
||||
outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
|
||||
|
||||
if (vt596_transaction(size)) /* Error in transaction */
|
||||
return -1;
|
||||
status = vt596_transaction(size);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
|
||||
return 0;
|
||||
|
@ -285,9 +286,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
|||
return 0;
|
||||
|
||||
exit_unsupported:
|
||||
dev_warn(&vt596_adapter.dev, "Unsupported command invoked! (0x%02x)\n",
|
||||
dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
|
||||
size);
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static u32 vt596_func(struct i2c_adapter *adapter)
|
||||
|
@ -309,7 +310,7 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
static struct i2c_adapter vt596_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_SMBUS_VIA2,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo = &smbus_algorithm,
|
||||
};
|
||||
|
||||
|
@ -354,6 +355,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
found:
|
||||
error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!request_region(vt596_smba, 8, vt596_driver.name)) {
|
||||
dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
|
||||
vt596_smba);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
voodoo3.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Ralph Metzler <rjkm@thp.uni-koeln.de>, and
|
||||
|
|
|
@ -442,7 +442,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
|
|||
adapter->owner = THIS_MODULE;
|
||||
adapter->id = I2C_HW_SMBUS_SCX200;
|
||||
adapter->algo = &scx200_acb_algorithm;
|
||||
adapter->class = I2C_CLASS_HWMON;
|
||||
adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adapter->dev.parent = dev;
|
||||
|
||||
mutex_init(&iface->mutex);
|
||||
|
|
|
@ -14,6 +14,32 @@ config DS1682
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called ds1682.
|
||||
|
||||
config AT24
|
||||
tristate "EEPROMs from most vendors"
|
||||
depends on SYSFS && EXPERIMENTAL
|
||||
help
|
||||
Enable this driver to get read/write support to most I2C EEPROMs,
|
||||
after you configure the driver to know about each EEPROM on
|
||||
your target board. Use these generic chip names, instead of
|
||||
vendor-specific ones like at24c64 or 24lc02:
|
||||
|
||||
24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
|
||||
24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
|
||||
|
||||
Unless you like data loss puzzles, always be sure that any chip
|
||||
you configure as a 24c32 (32 kbit) or larger is NOT really a
|
||||
24c16 (16 kbit) or smaller, and vice versa. Marking the chip
|
||||
as read-only won't help recover from this. Also, if your chip
|
||||
has any software write-protect mechanism you may want to review the
|
||||
code to make sure this driver won't turn it on by accident.
|
||||
|
||||
If you use this with an SMBus adapter instead of an I2C adapter,
|
||||
full functionality is not available. Only smaller devices are
|
||||
supported (24c16 and below, max 4 kByte).
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called at24.
|
||||
|
||||
config SENSORS_EEPROM
|
||||
tristate "EEPROM reader"
|
||||
depends on EXPERIMENTAL
|
||||
|
@ -26,8 +52,8 @@ config SENSORS_EEPROM
|
|||
will be called eeprom.
|
||||
|
||||
config SENSORS_PCF8574
|
||||
tristate "Philips PCF8574 and PCF8574A"
|
||||
depends on EXPERIMENTAL
|
||||
tristate "Philips PCF8574 and PCF8574A (DEPRECATED)"
|
||||
depends on EXPERIMENTAL && GPIO_PCF857X = "n"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Philips PCF8574 and
|
||||
|
@ -36,12 +62,16 @@ config SENSORS_PCF8574
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called pcf8574.
|
||||
|
||||
This driver is deprecated and will be dropped soon. Use
|
||||
drivers/gpio/pcf857x.c instead.
|
||||
|
||||
These devices are hard to detect and rarely found on mainstream
|
||||
hardware. If unsure, say N.
|
||||
|
||||
config PCF8575
|
||||
tristate "Philips PCF8575"
|
||||
tristate "Philips PCF8575 (DEPRECATED)"
|
||||
default n
|
||||
depends on GPIO_PCF857X = "n"
|
||||
help
|
||||
If you say yes here you get support for Philips PCF8575 chip.
|
||||
This chip is a 16-bit I/O expander for the I2C bus. Several other
|
||||
|
@ -50,12 +80,15 @@ config PCF8575
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called pcf8575.
|
||||
|
||||
This driver is deprecated and will be dropped soon. Use
|
||||
drivers/gpio/pcf857x.c instead.
|
||||
|
||||
This device is hard to detect and is rarely found on mainstream
|
||||
hardware. If unsure, say N.
|
||||
|
||||
config SENSORS_PCA9539
|
||||
tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)"
|
||||
depends on EXPERIMENTAL && GPIO_PCA9539 = "n"
|
||||
depends on EXPERIMENTAL && GPIO_PCA953X = "n"
|
||||
help
|
||||
If you say yes here you get support for the Philips PCA9539
|
||||
16-bit I/O port.
|
||||
|
@ -64,7 +97,7 @@ config SENSORS_PCA9539
|
|||
will be called pca9539.
|
||||
|
||||
This driver is deprecated and will be dropped soon. Use
|
||||
drivers/gpio/pca9539.c instead.
|
||||
drivers/gpio/pca953x.c instead.
|
||||
|
||||
config SENSORS_PCF8591
|
||||
tristate "Philips PCF8591"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_DS1682) += ds1682.o
|
||||
obj-$(CONFIG_AT24) += at24.o
|
||||
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
|
||||
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
||||
|
|
583
drivers/i2c/chips/at24.c
Normal file
583
drivers/i2c/chips/at24.c
Normal file
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
* at24.c - handle most I2C EEPROMs
|
||||
*
|
||||
* Copyright (C) 2005-2007 David Brownell
|
||||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
|
||||
/*
|
||||
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
|
||||
* Differences between different vendor product lines (like Atmel AT24C or
|
||||
* MicroChip 24LC, etc) won't much matter for typical read/write access.
|
||||
* There are also I2C RAM chips, likewise interchangeable. One example
|
||||
* would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
|
||||
*
|
||||
* However, misconfiguration can lose data. "Set 16-bit memory address"
|
||||
* to a part with 8-bit addressing will overwrite data. Writing with too
|
||||
* big a page size also loses data. And it's not safe to assume that the
|
||||
* conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
|
||||
* uses 0x51, for just one example.
|
||||
*
|
||||
* Accordingly, explicit board-specific configuration data should be used
|
||||
* in almost all cases. (One partial exception is an SMBus used to access
|
||||
* "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
|
||||
*
|
||||
* So this driver uses "new style" I2C driver binding, expecting to be
|
||||
* told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
|
||||
* similar kernel-resident tables; or, configuration data coming from
|
||||
* a bootloader.
|
||||
*
|
||||
* Other than binding model, current differences from "eeprom" driver are
|
||||
* that this one handles write access and isn't restricted to 24c02 devices.
|
||||
* It also handles larger devices (32 kbit and up) with two-byte addresses,
|
||||
* which won't work on pure SMBus systems.
|
||||
*/
|
||||
|
||||
struct at24_data {
|
||||
struct at24_platform_data chip;
|
||||
bool use_smbus;
|
||||
|
||||
/*
|
||||
* Lock protects against activities from other Linux tasks,
|
||||
* but not from changes by other I2C masters.
|
||||
*/
|
||||
struct mutex lock;
|
||||
struct bin_attribute bin;
|
||||
|
||||
u8 *writebuf;
|
||||
unsigned write_max;
|
||||
unsigned num_addresses;
|
||||
|
||||
/*
|
||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
||||
* them for us, and we'll use them with SMBus calls.
|
||||
*/
|
||||
struct i2c_client *client[];
|
||||
};
|
||||
|
||||
/*
|
||||
* This parameter is to help this driver avoid blocking other drivers out
|
||||
* of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
|
||||
* clock, one 256 byte read takes about 1/43 second which is excessive;
|
||||
* but the 1/170 second it takes at 400 kHz may be quite reasonable; and
|
||||
* at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
|
||||
*
|
||||
* This value is forced to be a power of two so that writes align on pages.
|
||||
*/
|
||||
static unsigned io_limit = 128;
|
||||
module_param(io_limit, uint, 0);
|
||||
MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
|
||||
|
||||
/*
|
||||
* Specs often allow 5 msec for a page write, sometimes 20 msec;
|
||||
* it's important to recover from write timeouts.
|
||||
*/
|
||||
static unsigned write_timeout = 25;
|
||||
module_param(write_timeout, uint, 0);
|
||||
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
|
||||
|
||||
#define AT24_SIZE_BYTELEN 5
|
||||
#define AT24_SIZE_FLAGS 8
|
||||
|
||||
#define AT24_BITMASK(x) (BIT(x) - 1)
|
||||
|
||||
/* create non-zero magic value for given eeprom parameters */
|
||||
#define AT24_DEVICE_MAGIC(_len, _flags) \
|
||||
((1 << AT24_SIZE_FLAGS | (_flags)) \
|
||||
<< AT24_SIZE_BYTELEN | ilog2(_len))
|
||||
|
||||
static const struct i2c_device_id at24_ids[] = {
|
||||
/* needs 8 addresses as A0-A2 are ignored */
|
||||
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
|
||||
/* old variants can't be handled with this generic entry! */
|
||||
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
|
||||
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
|
||||
/* spd is a 24c02 in memory DIMMs */
|
||||
{ "spd", AT24_DEVICE_MAGIC(2048 / 8,
|
||||
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
|
||||
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
|
||||
/* 24rf08 quirk is handled at i2c-core */
|
||||
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
|
||||
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
|
||||
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
|
||||
{ "at24", 0 },
|
||||
{ /* END OF LIST */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, at24_ids);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* This routine supports chips which consume multiple I2C addresses. It
|
||||
* computes the addressing information to be used for a given r/w request.
|
||||
* Assumes that sanity checks for offset happened at sysfs-layer.
|
||||
*/
|
||||
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
|
||||
unsigned *offset)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (at24->chip.flags & AT24_FLAG_ADDR16) {
|
||||
i = *offset >> 16;
|
||||
*offset &= 0xffff;
|
||||
} else {
|
||||
i = *offset >> 8;
|
||||
*offset &= 0xff;
|
||||
}
|
||||
|
||||
return at24->client[i];
|
||||
}
|
||||
|
||||
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
|
||||
unsigned offset, size_t count)
|
||||
{
|
||||
struct i2c_msg msg[2];
|
||||
u8 msgbuf[2];
|
||||
struct i2c_client *client;
|
||||
int status, i;
|
||||
|
||||
memset(msg, 0, sizeof(msg));
|
||||
|
||||
/*
|
||||
* REVISIT some multi-address chips don't rollover page reads to
|
||||
* the next slave address, so we may need to truncate the count.
|
||||
* Those chips might need another quirk flag.
|
||||
*
|
||||
* If the real hardware used four adjacent 24c02 chips and that
|
||||
* were misconfigured as one 24c08, that would be a similar effect:
|
||||
* one "eeprom" file not four, but larger reads would fail when
|
||||
* they crossed certain pages.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Slave address and byte offset derive from the offset. Always
|
||||
* set the byte address; on a multi-master board, another master
|
||||
* may have changed the chip's "current" address pointer.
|
||||
*/
|
||||
client = at24_translate_offset(at24, &offset);
|
||||
|
||||
if (count > io_limit)
|
||||
count = io_limit;
|
||||
|
||||
/* Smaller eeproms can work given some SMBus extension calls */
|
||||
if (at24->use_smbus) {
|
||||
if (count > I2C_SMBUS_BLOCK_MAX)
|
||||
count = I2C_SMBUS_BLOCK_MAX;
|
||||
status = i2c_smbus_read_i2c_block_data(client, offset,
|
||||
count, buf);
|
||||
dev_dbg(&client->dev, "smbus read %zd@%d --> %d\n",
|
||||
count, offset, status);
|
||||
return (status < 0) ? -EIO : status;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we have a better choice than SMBus calls, use a combined
|
||||
* I2C message. Write address; then read up to io_limit data bytes.
|
||||
* Note that read page rollover helps us here (unlike writes).
|
||||
* msgbuf is u8 and will cast to our needs.
|
||||
*/
|
||||
i = 0;
|
||||
if (at24->chip.flags & AT24_FLAG_ADDR16)
|
||||
msgbuf[i++] = offset >> 8;
|
||||
msgbuf[i++] = offset;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].buf = msgbuf;
|
||||
msg[0].len = i;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].buf = buf;
|
||||
msg[1].len = count;
|
||||
|
||||
status = i2c_transfer(client->adapter, msg, 2);
|
||||
dev_dbg(&client->dev, "i2c read %zd@%d --> %d\n",
|
||||
count, offset, status);
|
||||
|
||||
if (status == 2)
|
||||
return count;
|
||||
else if (status >= 0)
|
||||
return -EIO;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct at24_data *at24;
|
||||
ssize_t retval = 0;
|
||||
|
||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
||||
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
/*
|
||||
* Read data from chip, protecting against concurrent updates
|
||||
* from this host, but not from other I2C masters.
|
||||
*/
|
||||
mutex_lock(&at24->lock);
|
||||
|
||||
while (count) {
|
||||
ssize_t status;
|
||||
|
||||
status = at24_eeprom_read(at24, buf, off, count);
|
||||
if (status <= 0) {
|
||||
if (retval == 0)
|
||||
retval = status;
|
||||
break;
|
||||
}
|
||||
buf += status;
|
||||
off += status;
|
||||
count -= status;
|
||||
retval += status;
|
||||
}
|
||||
|
||||
mutex_unlock(&at24->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* REVISIT: export at24_bin{read,write}() to let other kernel code use
|
||||
* eeprom data. For example, it might hold a board's Ethernet address, or
|
||||
* board-specific calibration data generated on the manufacturing floor.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Note that if the hardware write-protect pin is pulled high, the whole
|
||||
* chip is normally write protected. But there are plenty of product
|
||||
* variants here, including OTP fuses and partial chip protect.
|
||||
*
|
||||
* We only use page mode writes; the alternative is sloooow. This routine
|
||||
* writes at most one page.
|
||||
*/
|
||||
static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf,
|
||||
unsigned offset, size_t count)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_msg msg;
|
||||
ssize_t status;
|
||||
unsigned long timeout, write_time;
|
||||
unsigned next_page;
|
||||
|
||||
/* Get corresponding I2C address and adjust offset */
|
||||
client = at24_translate_offset(at24, &offset);
|
||||
|
||||
/* write_max is at most a page */
|
||||
if (count > at24->write_max)
|
||||
count = at24->write_max;
|
||||
|
||||
/* Never roll over backwards, to the start of this page */
|
||||
next_page = roundup(offset + 1, at24->chip.page_size);
|
||||
if (offset + count > next_page)
|
||||
count = next_page - offset;
|
||||
|
||||
/* If we'll use I2C calls for I/O, set up the message */
|
||||
if (!at24->use_smbus) {
|
||||
int i = 0;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = 0;
|
||||
|
||||
/* msg.buf is u8 and casts will mask the values */
|
||||
msg.buf = at24->writebuf;
|
||||
if (at24->chip.flags & AT24_FLAG_ADDR16)
|
||||
msg.buf[i++] = offset >> 8;
|
||||
|
||||
msg.buf[i++] = offset;
|
||||
memcpy(&msg.buf[i], buf, count);
|
||||
msg.len = i + count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes fail if the previous one didn't complete yet. We may
|
||||
* loop a few times until this one succeeds, waiting at least
|
||||
* long enough for one entire page write to work.
|
||||
*/
|
||||
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
||||
do {
|
||||
write_time = jiffies;
|
||||
if (at24->use_smbus) {
|
||||
status = i2c_smbus_write_i2c_block_data(client,
|
||||
offset, count, buf);
|
||||
if (status == 0)
|
||||
status = count;
|
||||
} else {
|
||||
status = i2c_transfer(client->adapter, &msg, 1);
|
||||
if (status == 1)
|
||||
status = count;
|
||||
}
|
||||
dev_dbg(&client->dev, "write %zd@%d --> %zd (%ld)\n",
|
||||
count, offset, status, jiffies);
|
||||
|
||||
if (status == count)
|
||||
return count;
|
||||
|
||||
/* REVISIT: at HZ=100, this is sloooow */
|
||||
msleep(1);
|
||||
} while (time_before(write_time, timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct at24_data *at24;
|
||||
ssize_t retval = 0;
|
||||
|
||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
||||
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
/*
|
||||
* Write data to chip, protecting against concurrent updates
|
||||
* from this host, but not from other I2C masters.
|
||||
*/
|
||||
mutex_lock(&at24->lock);
|
||||
|
||||
while (count) {
|
||||
ssize_t status;
|
||||
|
||||
status = at24_eeprom_write(at24, buf, off, count);
|
||||
if (status <= 0) {
|
||||
if (retval == 0)
|
||||
retval = status;
|
||||
break;
|
||||
}
|
||||
buf += status;
|
||||
off += status;
|
||||
count -= status;
|
||||
retval += status;
|
||||
}
|
||||
|
||||
mutex_unlock(&at24->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct at24_platform_data chip;
|
||||
bool writable;
|
||||
bool use_smbus = false;
|
||||
struct at24_data *at24;
|
||||
int err;
|
||||
unsigned i, num_addresses;
|
||||
kernel_ulong_t magic;
|
||||
|
||||
if (client->dev.platform_data) {
|
||||
chip = *(struct at24_platform_data *)client->dev.platform_data;
|
||||
} else {
|
||||
if (!id->driver_data) {
|
||||
err = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
magic = id->driver_data;
|
||||
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
|
||||
magic >>= AT24_SIZE_BYTELEN;
|
||||
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
|
||||
/*
|
||||
* This is slow, but we can't know all eeproms, so we better
|
||||
* play safe. Specifying custom eeprom-types via platform_data
|
||||
* is recommended anyhow.
|
||||
*/
|
||||
chip.page_size = 1;
|
||||
}
|
||||
|
||||
if (!is_power_of_2(chip.byte_len))
|
||||
dev_warn(&client->dev,
|
||||
"byte_len looks suspicious (no power of 2)!\n");
|
||||
if (!is_power_of_2(chip.page_size))
|
||||
dev_warn(&client->dev,
|
||||
"page_size looks suspicious (no power of 2)!\n");
|
||||
|
||||
/* Use I2C operations unless we're stuck with SMBus extensions. */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
if (chip.flags & AT24_FLAG_ADDR16) {
|
||||
err = -EPFNOSUPPORT;
|
||||
goto err_out;
|
||||
}
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
err = -EPFNOSUPPORT;
|
||||
goto err_out;
|
||||
}
|
||||
use_smbus = true;
|
||||
}
|
||||
|
||||
if (chip.flags & AT24_FLAG_TAKE8ADDR)
|
||||
num_addresses = 8;
|
||||
else
|
||||
num_addresses = DIV_ROUND_UP(chip.byte_len,
|
||||
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
|
||||
|
||||
at24 = kzalloc(sizeof(struct at24_data) +
|
||||
num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
|
||||
if (!at24) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
mutex_init(&at24->lock);
|
||||
at24->use_smbus = use_smbus;
|
||||
at24->chip = chip;
|
||||
at24->num_addresses = num_addresses;
|
||||
|
||||
/*
|
||||
* Export the EEPROM bytes through sysfs, since that's convenient.
|
||||
* By default, only root should see the data (maybe passwords etc)
|
||||
*/
|
||||
at24->bin.attr.name = "eeprom";
|
||||
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
|
||||
at24->bin.attr.owner = THIS_MODULE;
|
||||
at24->bin.read = at24_bin_read;
|
||||
at24->bin.size = chip.byte_len;
|
||||
|
||||
writable = !(chip.flags & AT24_FLAG_READONLY);
|
||||
if (writable) {
|
||||
if (!use_smbus || i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
|
||||
|
||||
unsigned write_max = chip.page_size;
|
||||
|
||||
at24->bin.write = at24_bin_write;
|
||||
at24->bin.attr.mode |= S_IWUSR;
|
||||
|
||||
if (write_max > io_limit)
|
||||
write_max = io_limit;
|
||||
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
|
||||
write_max = I2C_SMBUS_BLOCK_MAX;
|
||||
at24->write_max = write_max;
|
||||
|
||||
/* buffer (data + address at the beginning) */
|
||||
at24->writebuf = kmalloc(write_max + 2, GFP_KERNEL);
|
||||
if (!at24->writebuf) {
|
||||
err = -ENOMEM;
|
||||
goto err_struct;
|
||||
}
|
||||
} else {
|
||||
dev_warn(&client->dev,
|
||||
"cannot write due to controller restrictions.");
|
||||
}
|
||||
}
|
||||
|
||||
at24->client[0] = client;
|
||||
|
||||
/* use dummy devices for multiple-address chips */
|
||||
for (i = 1; i < num_addresses; i++) {
|
||||
at24->client[i] = i2c_new_dummy(client->adapter,
|
||||
client->addr + i);
|
||||
if (!at24->client[i]) {
|
||||
dev_err(&client->dev, "address 0x%02x unavailable\n",
|
||||
client->addr + i);
|
||||
err = -EADDRINUSE;
|
||||
goto err_clients;
|
||||
}
|
||||
}
|
||||
|
||||
err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
|
||||
if (err)
|
||||
goto err_clients;
|
||||
|
||||
i2c_set_clientdata(client, at24);
|
||||
|
||||
dev_info(&client->dev, "%Zd byte %s EEPROM %s\n",
|
||||
at24->bin.size, client->name,
|
||||
writable ? "(writable)" : "(read-only)");
|
||||
dev_dbg(&client->dev,
|
||||
"page_size %d, num_addresses %d, write_max %d%s\n",
|
||||
chip.page_size, num_addresses,
|
||||
at24->write_max,
|
||||
use_smbus ? ", use_smbus" : "");
|
||||
|
||||
return 0;
|
||||
|
||||
err_clients:
|
||||
for (i = 1; i < num_addresses; i++)
|
||||
if (at24->client[i])
|
||||
i2c_unregister_device(at24->client[i]);
|
||||
|
||||
kfree(at24->writebuf);
|
||||
err_struct:
|
||||
kfree(at24);
|
||||
err_out:
|
||||
dev_dbg(&client->dev, "probe error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit at24_remove(struct i2c_client *client)
|
||||
{
|
||||
struct at24_data *at24;
|
||||
int i;
|
||||
|
||||
at24 = i2c_get_clientdata(client);
|
||||
sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
|
||||
|
||||
for (i = 1; i < at24->num_addresses; i++)
|
||||
i2c_unregister_device(at24->client[i]);
|
||||
|
||||
kfree(at24->writebuf);
|
||||
kfree(at24);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct i2c_driver at24_driver = {
|
||||
.driver = {
|
||||
.name = "at24",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = at24_probe,
|
||||
.remove = __devexit_p(at24_remove),
|
||||
.id_table = at24_ids,
|
||||
};
|
||||
|
||||
static int __init at24_init(void)
|
||||
{
|
||||
io_limit = rounddown_pow_of_two(io_limit);
|
||||
return i2c_add_driver(&at24_driver);
|
||||
}
|
||||
module_init(at24_init);
|
||||
|
||||
static void __exit at24_exit(void)
|
||||
{
|
||||
i2c_del_driver(&at24_driver);
|
||||
}
|
||||
module_exit(at24_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
|
||||
MODULE_AUTHOR("David Brownell and Wolfram Sang");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,15 +1,9 @@
|
|||
/*
|
||||
eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
|
||||
Copyright (C) 2003 IBM Corp.
|
||||
|
||||
2004-01-16 Jean Delvare <khali@linux-fr.org>
|
||||
Divide the eeprom in 32-byte (arbitrary) slices. This significantly
|
||||
speeds sensors up, as well as various scripts using the eeprom
|
||||
module.
|
||||
Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -78,7 +72,7 @@ static struct i2c_driver eeprom_driver = {
|
|||
static void eeprom_update_client(struct i2c_client *client, u8 slice)
|
||||
{
|
||||
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
|
@ -93,15 +87,12 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice)
|
|||
!= 32)
|
||||
goto exit;
|
||||
} else {
|
||||
if (i2c_smbus_write_byte(client, slice << 5)) {
|
||||
dev_dbg(&client->dev, "eeprom read start has failed!\n");
|
||||
goto exit;
|
||||
}
|
||||
for (i = slice << 5; i < (slice + 1) << 5; i++) {
|
||||
j = i2c_smbus_read_byte(client);
|
||||
if (j < 0)
|
||||
for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
|
||||
int word = i2c_smbus_read_word_data(client, i);
|
||||
if (word < 0)
|
||||
goto exit;
|
||||
data->data[i] = (u8) j;
|
||||
data->data[i] = word & 0xff;
|
||||
data->data[i + 1] = word >> 8;
|
||||
}
|
||||
}
|
||||
data->last_updated[slice] = jiffies;
|
||||
|
@ -159,24 +150,33 @@ static struct bin_attribute eeprom_attr = {
|
|||
|
||||
static int eeprom_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & (I2C_CLASS_DDC | I2C_CLASS_SPD)))
|
||||
return 0;
|
||||
return i2c_probe(adapter, &addr_data, eeprom_detect);
|
||||
}
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct eeprom_data *data;
|
||||
int err = 0;
|
||||
|
||||
/* There are three ways we can read the EEPROM data:
|
||||
/* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
|
||||
addresses 0x50-0x57, but we only care about 0x50. So decline
|
||||
attaching to addresses >= 0x51 on DDC buses */
|
||||
if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51)
|
||||
goto exit;
|
||||
|
||||
/* There are four ways we can read the EEPROM data:
|
||||
(1) I2C block reads (faster, but unsupported by most adapters)
|
||||
(2) Consecutive byte reads (100% overhead)
|
||||
(3) Regular byte data reads (200% overhead)
|
||||
The third method is not implemented by this driver because all
|
||||
known adapters support at least the second. */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA
|
||||
| I2C_FUNC_SMBUS_BYTE))
|
||||
(2) Word reads (128% overhead)
|
||||
(3) Consecutive byte reads (88% overhead, unsafe)
|
||||
(4) Regular byte data reads (265% overhead)
|
||||
The third and fourth methods are not implemented by this driver
|
||||
because all known adapters support one of the first two. */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
|
||||
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
|
||||
goto exit;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
|
||||
|
@ -184,50 +184,49 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
client = &data->client;
|
||||
memset(data->data, 0xff, EEPROM_SIZE);
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &eeprom_driver;
|
||||
new_client->flags = 0;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &eeprom_driver;
|
||||
|
||||
/* Fill in the remaining client fields */
|
||||
strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE);
|
||||
data->valid = 0;
|
||||
strlcpy(client->name, "eeprom", I2C_NAME_SIZE);
|
||||
mutex_init(&data->update_lock);
|
||||
data->nature = UNKNOWN;
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Detect the Vaio nature of EEPROMs.
|
||||
We use the "PCG-" or "VGN-" prefix as the signature. */
|
||||
if (address == 0x57) {
|
||||
if (address == 0x57
|
||||
&& i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
||||
char name[4];
|
||||
|
||||
name[0] = i2c_smbus_read_byte_data(new_client, 0x80);
|
||||
name[1] = i2c_smbus_read_byte(new_client);
|
||||
name[2] = i2c_smbus_read_byte(new_client);
|
||||
name[3] = i2c_smbus_read_byte(new_client);
|
||||
name[0] = i2c_smbus_read_byte_data(client, 0x80);
|
||||
name[1] = i2c_smbus_read_byte_data(client, 0x81);
|
||||
name[2] = i2c_smbus_read_byte_data(client, 0x82);
|
||||
name[3] = i2c_smbus_read_byte_data(client, 0x83);
|
||||
|
||||
if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
|
||||
dev_info(&new_client->dev, "Vaio EEPROM detected, "
|
||||
dev_info(&client->dev, "Vaio EEPROM detected, "
|
||||
"enabling privacy protection\n");
|
||||
data->nature = VAIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* create the sysfs eeprom file */
|
||||
err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
|
||||
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
|
|
@ -170,7 +170,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
struct i2c_client *real_client;
|
||||
struct i2c_client *fake_client;
|
||||
struct max6875_data *data;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
||||
| I2C_FUNC_SMBUS_READ_BYTE))
|
||||
|
@ -195,7 +195,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
real_client->addr = address;
|
||||
real_client->adapter = adapter;
|
||||
real_client->driver = &max6875_driver;
|
||||
real_client->flags = 0;
|
||||
strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
|
@ -204,7 +203,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
fake_client->addr = address | 1;
|
||||
fake_client->adapter = adapter;
|
||||
fake_client->driver = &max6875_driver;
|
||||
fake_client->flags = 0;
|
||||
strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
|
||||
|
||||
if ((err = i2c_attach_client(real_client)) != 0)
|
||||
|
|
|
@ -113,7 +113,7 @@ static int pca9539_attach_adapter(struct i2c_adapter *adapter)
|
|||
/* This function is called by i2c_probe */
|
||||
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct pca9539_data *data;
|
||||
int err = 0;
|
||||
|
||||
|
@ -127,29 +127,28 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &pca9539_driver;
|
||||
new_client->flags = 0;
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &pca9539_driver;
|
||||
|
||||
if (kind < 0) {
|
||||
/* Detection: the pca9539 only has 8 registers (0-7).
|
||||
A read of 7 should succeed, but a read of 8 should fail. */
|
||||
if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
|
||||
(i2c_smbus_read_byte_data(new_client, 8) >= 0))
|
||||
if ((i2c_smbus_read_byte_data(client, 7) < 0) ||
|
||||
(i2c_smbus_read_byte_data(client, 8) >= 0))
|
||||
goto exit_kfree;
|
||||
}
|
||||
|
||||
strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
|
||||
strlcpy(client->name, "pca9539", I2C_NAME_SIZE);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj,
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&pca9539_defattr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
@ -157,7 +156,7 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
return 0;
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Dan Eaton <dan.eaton@rocketlogix.com>
|
||||
|
@ -129,7 +127,7 @@ static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
|
|||
/* This function is called by i2c_probe */
|
||||
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct pcf8574_data *data;
|
||||
int err = 0;
|
||||
const char *client_name = "";
|
||||
|
@ -144,12 +142,11 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &pcf8574_driver;
|
||||
new_client->flags = 0;
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &pcf8574_driver;
|
||||
|
||||
/* Now, we would do the remaining detection. But the PCF8574 is plainly
|
||||
impossible to detect! Stupid chip. */
|
||||
|
@ -168,23 +165,23 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
client_name = "pcf8574";
|
||||
|
||||
/* Fill in the remaining client fields and put it into the global list */
|
||||
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
|
||||
strlcpy(client->name, client_name, I2C_NAME_SIZE);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_free;
|
||||
|
||||
/* Initialize the PCF8574 chip */
|
||||
pcf8574_init_client(new_client);
|
||||
pcf8574_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
|
||||
err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
|
||||
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
the help of Jean Delvare <khali@linux-fr.org>
|
||||
|
@ -190,7 +188,7 @@ static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
|
|||
/* This function is called by i2c_probe */
|
||||
static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct pcf8591_data *data;
|
||||
int err = 0;
|
||||
|
||||
|
@ -205,12 +203,11 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &pcf8591_driver;
|
||||
new_client->flags = 0;
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &pcf8591_driver;
|
||||
|
||||
/* Now, we would do the remaining detection. But the PCF8591 is plainly
|
||||
impossible to detect! Stupid chip. */
|
||||
|
@ -221,31 +218,31 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
|
||||
/* Fill in the remaining client fields and put it into the global
|
||||
list */
|
||||
strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE);
|
||||
strlcpy(client->name, "pcf8591", I2C_NAME_SIZE);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Initialize the PCF8591 chip */
|
||||
pcf8591_init_client(new_client);
|
||||
pcf8591_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
|
||||
err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
|
||||
/* Register input2 if not in "two differential inputs" mode */
|
||||
if (input_mode != 3) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&dev_attr_in2_input)))
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
||||
/* Register input3 only in "four single ended inputs" mode */
|
||||
if (input_mode == 0) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&dev_attr_in3_input)))
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
@ -253,10 +250,10 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
return 0;
|
||||
|
||||
exit_sysfs_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
|
|
@ -29,13 +29,11 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "i2c-core.h"
|
||||
|
@ -44,7 +42,9 @@
|
|||
static DEFINE_MUTEX(core_lock);
|
||||
static DEFINE_IDR(i2c_adapter_idr);
|
||||
|
||||
#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
|
||||
#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect)
|
||||
|
||||
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -103,19 +103,14 @@ static int i2c_device_probe(struct device *dev)
|
|||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_driver *driver = to_i2c_driver(dev->driver);
|
||||
const struct i2c_device_id *id;
|
||||
int status;
|
||||
|
||||
if (!driver->probe)
|
||||
if (!driver->probe || !driver->id_table)
|
||||
return -ENODEV;
|
||||
client->driver = driver;
|
||||
dev_dbg(dev, "probe\n");
|
||||
|
||||
if (driver->id_table)
|
||||
id = i2c_match_id(driver->id_table, client);
|
||||
else
|
||||
id = NULL;
|
||||
status = driver->probe(client, id);
|
||||
status = driver->probe(client, i2c_match_id(driver->id_table, client));
|
||||
if (status)
|
||||
client->driver = NULL;
|
||||
return status;
|
||||
|
@ -208,7 +203,7 @@ static struct device_attribute i2c_dev_attrs[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
static struct bus_type i2c_bus_type = {
|
||||
struct bus_type i2c_bus_type = {
|
||||
.name = "i2c",
|
||||
.dev_attrs = i2c_dev_attrs,
|
||||
.match = i2c_device_match,
|
||||
|
@ -219,6 +214,7 @@ static struct bus_type i2c_bus_type = {
|
|||
.suspend = i2c_device_suspend,
|
||||
.resume = i2c_device_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(i2c_bus_type);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -306,6 +302,14 @@ void i2c_unregister_device(struct i2c_client *client)
|
|||
return;
|
||||
}
|
||||
|
||||
if (adapter->client_unregister) {
|
||||
if (adapter->client_unregister(client)) {
|
||||
dev_warn(&client->dev,
|
||||
"client_unregister [%s] failed\n",
|
||||
client->name);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&adapter->clist_lock);
|
||||
list_del(&client->list);
|
||||
mutex_unlock(&adapter->clist_lock);
|
||||
|
@ -416,6 +420,10 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data)
|
|||
struct i2c_driver *driver = to_i2c_driver(d);
|
||||
struct i2c_adapter *adap = data;
|
||||
|
||||
/* Detect supported devices on that bus, and instantiate them */
|
||||
i2c_detect(adap, driver);
|
||||
|
||||
/* Let legacy drivers scan this bus for matching devices */
|
||||
if (driver->attach_adapter) {
|
||||
/* We ignore the return code; if it fails, too bad */
|
||||
driver->attach_adapter(adap);
|
||||
|
@ -455,7 +463,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
if (adap->nr < __i2c_first_dynamic_bus_num)
|
||||
i2c_scan_static_board_info(adap);
|
||||
|
||||
/* let legacy drivers scan this bus for matching devices */
|
||||
/* Notify drivers */
|
||||
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
|
||||
i2c_do_add_adapter);
|
||||
|
||||
|
@ -561,8 +569,19 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data)
|
|||
{
|
||||
struct i2c_driver *driver = to_i2c_driver(d);
|
||||
struct i2c_adapter *adapter = data;
|
||||
struct i2c_client *client, *_n;
|
||||
int res;
|
||||
|
||||
/* Remove the devices we created ourselves */
|
||||
list_for_each_entry_safe(client, _n, &driver->clients, detected) {
|
||||
if (client->adapter == adapter) {
|
||||
dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
|
||||
client->name, client->addr);
|
||||
list_del(&client->detected);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (!driver->detach_adapter)
|
||||
return 0;
|
||||
res = driver->detach_adapter(adapter);
|
||||
|
@ -582,8 +601,7 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data)
|
|||
*/
|
||||
int i2c_del_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct list_head *item, *_n;
|
||||
struct i2c_client *client;
|
||||
struct i2c_client *client, *_n;
|
||||
int res = 0;
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
|
@ -604,10 +622,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
|||
|
||||
/* detach any active clients. This must be done first, because
|
||||
* it can fail; in which case we give up. */
|
||||
list_for_each_safe(item, _n, &adap->clients) {
|
||||
list_for_each_entry_safe(client, _n, &adap->clients, list) {
|
||||
struct i2c_driver *driver;
|
||||
|
||||
client = list_entry(item, struct i2c_client, list);
|
||||
driver = client->driver;
|
||||
|
||||
/* new style, follow standard driver model */
|
||||
|
@ -646,6 +663,20 @@ EXPORT_SYMBOL(i2c_del_adapter);
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int __attach_adapter(struct device *dev, void *data)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(dev);
|
||||
struct i2c_driver *driver = data;
|
||||
|
||||
i2c_detect(adapter, driver);
|
||||
|
||||
/* Legacy drivers scan i2c busses directly */
|
||||
if (driver->attach_adapter)
|
||||
driver->attach_adapter(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* An i2c_driver is used with one or more i2c_client (device) nodes to access
|
||||
* i2c slave chips, on a bus instance associated with some i2c_adapter. There
|
||||
|
@ -685,23 +716,59 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
|
|||
|
||||
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
|
||||
|
||||
/* legacy drivers scan i2c busses directly */
|
||||
if (driver->attach_adapter) {
|
||||
struct i2c_adapter *adapter;
|
||||
|
||||
down(&i2c_adapter_class.sem);
|
||||
list_for_each_entry(adapter, &i2c_adapter_class.devices,
|
||||
dev.node) {
|
||||
driver->attach_adapter(adapter);
|
||||
}
|
||||
up(&i2c_adapter_class.sem);
|
||||
}
|
||||
INIT_LIST_HEAD(&driver->clients);
|
||||
/* Walk the adapters that are already present */
|
||||
class_for_each_device(&i2c_adapter_class, driver, __attach_adapter);
|
||||
|
||||
mutex_unlock(&core_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_register_driver);
|
||||
|
||||
static int __detach_adapter(struct device *dev, void *data)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(dev);
|
||||
struct i2c_driver *driver = data;
|
||||
struct i2c_client *client, *_n;
|
||||
|
||||
list_for_each_entry_safe(client, _n, &driver->clients, detected) {
|
||||
dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
|
||||
client->name, client->addr);
|
||||
list_del(&client->detected);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
|
||||
if (is_newstyle_driver(driver))
|
||||
return 0;
|
||||
|
||||
/* Have a look at each adapter, if clients of this driver are still
|
||||
* attached. If so, detach them to be able to kill the driver
|
||||
* afterwards.
|
||||
*/
|
||||
if (driver->detach_adapter) {
|
||||
if (driver->detach_adapter(adapter))
|
||||
dev_err(&adapter->dev,
|
||||
"detach_adapter failed for driver [%s]\n",
|
||||
driver->driver.name);
|
||||
} else {
|
||||
struct i2c_client *client, *_n;
|
||||
|
||||
list_for_each_entry_safe(client, _n, &adapter->clients, list) {
|
||||
if (client->driver != driver)
|
||||
continue;
|
||||
dev_dbg(&adapter->dev,
|
||||
"detaching client [%s] at 0x%02x\n",
|
||||
client->name, client->addr);
|
||||
if (driver->detach_client(client))
|
||||
dev_err(&adapter->dev, "detach_client "
|
||||
"failed for client [%s] at 0x%02x\n",
|
||||
client->name, client->addr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_del_driver - unregister I2C driver
|
||||
* @driver: the driver being unregistered
|
||||
|
@ -709,48 +776,10 @@ EXPORT_SYMBOL(i2c_register_driver);
|
|||
*/
|
||||
void i2c_del_driver(struct i2c_driver *driver)
|
||||
{
|
||||
struct list_head *item2, *_n;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
|
||||
/* new-style driver? */
|
||||
if (is_newstyle_driver(driver))
|
||||
goto unregister;
|
||||
class_for_each_device(&i2c_adapter_class, driver, __detach_adapter);
|
||||
|
||||
/* Have a look at each adapter, if clients of this driver are still
|
||||
* attached. If so, detach them to be able to kill the driver
|
||||
* afterwards.
|
||||
*/
|
||||
down(&i2c_adapter_class.sem);
|
||||
list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
|
||||
if (driver->detach_adapter) {
|
||||
if (driver->detach_adapter(adap)) {
|
||||
dev_err(&adap->dev, "detach_adapter failed "
|
||||
"for driver [%s]\n",
|
||||
driver->driver.name);
|
||||
}
|
||||
} else {
|
||||
list_for_each_safe(item2, _n, &adap->clients) {
|
||||
client = list_entry(item2, struct i2c_client, list);
|
||||
if (client->driver != driver)
|
||||
continue;
|
||||
dev_dbg(&adap->dev, "detaching client [%s] "
|
||||
"at 0x%02x\n", client->name,
|
||||
client->addr);
|
||||
if (driver->detach_client(client)) {
|
||||
dev_err(&adap->dev, "detach_client "
|
||||
"failed for client [%s] at "
|
||||
"0x%02x\n", client->name,
|
||||
client->addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
up(&i2c_adapter_class.sem);
|
||||
|
||||
unregister:
|
||||
driver_unregister(&driver->driver);
|
||||
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
|
||||
|
||||
|
@ -863,8 +892,9 @@ EXPORT_SYMBOL(i2c_detach_client);
|
|||
*/
|
||||
struct i2c_client *i2c_use_client(struct i2c_client *client)
|
||||
{
|
||||
get_device(&client->dev);
|
||||
return client;
|
||||
if (client && get_device(&client->dev))
|
||||
return client;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_use_client);
|
||||
|
||||
|
@ -876,7 +906,8 @@ EXPORT_SYMBOL(i2c_use_client);
|
|||
*/
|
||||
void i2c_release_client(struct i2c_client *client)
|
||||
{
|
||||
put_device(&client->dev);
|
||||
if (client)
|
||||
put_device(&client->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_release_client);
|
||||
|
||||
|
@ -942,10 +973,39 @@ module_exit(i2c_exit);
|
|||
* ----------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* i2c_transfer - execute a single or combined I2C message
|
||||
* @adap: Handle to I2C bus
|
||||
* @msgs: One or more messages to execute before STOP is issued to
|
||||
* terminate the operation; each message begins with a START.
|
||||
* @num: Number of messages to be executed.
|
||||
*
|
||||
* Returns negative errno, else the number of messages executed.
|
||||
*
|
||||
* Note that there is no requirement that each message be sent to
|
||||
* the same slave address, although that is the most common model.
|
||||
*/
|
||||
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* REVISIT the fault reporting model here is weak:
|
||||
*
|
||||
* - When we get an error after receiving N bytes from a slave,
|
||||
* there is no way to report "N".
|
||||
*
|
||||
* - When we get a NAK after transmitting N bytes to a slave,
|
||||
* there is no way to report "N" ... or to let the master
|
||||
* continue executing the rest of this combined message, if
|
||||
* that's the appropriate response.
|
||||
*
|
||||
* - When for example "num" is two and we successfully complete
|
||||
* the first message but get an error part way through the
|
||||
* second, it's unclear whether that should be reported as
|
||||
* one (discarding status on the second message) or errno
|
||||
* (discarding status on the first one).
|
||||
*/
|
||||
|
||||
if (adap->algo->master_xfer) {
|
||||
#ifdef DEBUG
|
||||
for (ret = 0; ret < num; ret++) {
|
||||
|
@ -971,11 +1031,19 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
|
|||
return ret;
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
|
||||
return -ENOSYS;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_transfer);
|
||||
|
||||
/**
|
||||
* i2c_master_send - issue a single I2C message in master transmit mode
|
||||
* @client: Handle to slave device
|
||||
* @buf: Data that will be written to the slave
|
||||
* @count: How many bytes to write
|
||||
*
|
||||
* Returns negative errno, or else the number of bytes written.
|
||||
*/
|
||||
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
|
||||
{
|
||||
int ret;
|
||||
|
@ -995,6 +1063,14 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_master_send);
|
||||
|
||||
/**
|
||||
* i2c_master_recv - issue a single I2C message in master receive mode
|
||||
* @client: Handle to slave device
|
||||
* @buf: Where to store data read from slave
|
||||
* @count: How many bytes to read
|
||||
*
|
||||
* Returns negative errno, or else the number of bytes read.
|
||||
*/
|
||||
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
|
||||
{
|
||||
struct i2c_adapter *adap=client->adapter;
|
||||
|
@ -1103,7 +1179,7 @@ int i2c_probe(struct i2c_adapter *adapter,
|
|||
|
||||
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
|
||||
"can't probe for chips\n");
|
||||
return -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Probe entries are done second, and are not affected by ignore
|
||||
|
@ -1157,6 +1233,179 @@ int i2c_probe(struct i2c_adapter *adapter,
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_probe);
|
||||
|
||||
/* Separate detection function for new-style drivers */
|
||||
static int i2c_detect_address(struct i2c_client *temp_client, int kind,
|
||||
struct i2c_driver *driver)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter = temp_client->adapter;
|
||||
int addr = temp_client->addr;
|
||||
int err;
|
||||
|
||||
/* Make sure the address is valid */
|
||||
if (addr < 0x03 || addr > 0x77) {
|
||||
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
|
||||
addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Skip if already in use */
|
||||
if (i2c_check_addr(adapter, addr))
|
||||
return 0;
|
||||
|
||||
/* Make sure there is something at this address, unless forced */
|
||||
if (kind < 0) {
|
||||
if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
|
||||
I2C_SMBUS_QUICK, NULL) < 0)
|
||||
return 0;
|
||||
|
||||
/* prevent 24RF08 corruption */
|
||||
if ((addr & ~0x0f) == 0x50)
|
||||
i2c_smbus_xfer(adapter, addr, 0, 0, 0,
|
||||
I2C_SMBUS_QUICK, NULL);
|
||||
}
|
||||
|
||||
/* Finally call the custom detection function */
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = addr;
|
||||
err = driver->detect(temp_client, kind, &info);
|
||||
if (err) {
|
||||
/* -ENODEV is returned if the detection fails. We catch it
|
||||
here as this isn't an error. */
|
||||
return err == -ENODEV ? 0 : err;
|
||||
}
|
||||
|
||||
/* Consistency check */
|
||||
if (info.type[0] == '\0') {
|
||||
dev_err(&adapter->dev, "%s detection function provided "
|
||||
"no name for 0x%x\n", driver->driver.name,
|
||||
addr);
|
||||
} else {
|
||||
struct i2c_client *client;
|
||||
|
||||
/* Detection succeeded, instantiate the device */
|
||||
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
|
||||
info.type, info.addr);
|
||||
client = i2c_new_device(adapter, &info);
|
||||
if (client)
|
||||
list_add_tail(&client->detected, &driver->clients);
|
||||
else
|
||||
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
|
||||
info.type, info.addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
|
||||
{
|
||||
const struct i2c_client_address_data *address_data;
|
||||
struct i2c_client *temp_client;
|
||||
int i, err = 0;
|
||||
int adap_id = i2c_adapter_id(adapter);
|
||||
|
||||
address_data = driver->address_data;
|
||||
if (!driver->detect || !address_data)
|
||||
return 0;
|
||||
|
||||
/* Set up a temporary client to help detect callback */
|
||||
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!temp_client)
|
||||
return -ENOMEM;
|
||||
temp_client->adapter = adapter;
|
||||
|
||||
/* Force entries are done first, and are not affected by ignore
|
||||
entries */
|
||||
if (address_data->forces) {
|
||||
const unsigned short * const *forces = address_data->forces;
|
||||
int kind;
|
||||
|
||||
for (kind = 0; forces[kind]; kind++) {
|
||||
for (i = 0; forces[kind][i] != I2C_CLIENT_END;
|
||||
i += 2) {
|
||||
if (forces[kind][i] == adap_id
|
||||
|| forces[kind][i] == ANY_I2C_BUS) {
|
||||
dev_dbg(&adapter->dev, "found force "
|
||||
"parameter for adapter %d, "
|
||||
"addr 0x%02x, kind %d\n",
|
||||
adap_id, forces[kind][i + 1],
|
||||
kind);
|
||||
temp_client->addr = forces[kind][i + 1];
|
||||
err = i2c_detect_address(temp_client,
|
||||
kind, driver);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop here if we can't use SMBUS_QUICK */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
|
||||
if (address_data->probe[0] == I2C_CLIENT_END
|
||||
&& address_data->normal_i2c[0] == I2C_CLIENT_END)
|
||||
goto exit_free;
|
||||
|
||||
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
|
||||
"can't probe for chips\n");
|
||||
err = -EOPNOTSUPP;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* Stop here if the classes do not match */
|
||||
if (!(adapter->class & driver->class))
|
||||
goto exit_free;
|
||||
|
||||
/* Probe entries are done second, and are not affected by ignore
|
||||
entries either */
|
||||
for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
|
||||
if (address_data->probe[i] == adap_id
|
||||
|| address_data->probe[i] == ANY_I2C_BUS) {
|
||||
dev_dbg(&adapter->dev, "found probe parameter for "
|
||||
"adapter %d, addr 0x%02x\n", adap_id,
|
||||
address_data->probe[i + 1]);
|
||||
temp_client->addr = address_data->probe[i + 1];
|
||||
err = i2c_detect_address(temp_client, -1, driver);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normal entries are done last, unless shadowed by an ignore entry */
|
||||
for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
|
||||
int j, ignore;
|
||||
|
||||
ignore = 0;
|
||||
for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
|
||||
j += 2) {
|
||||
if ((address_data->ignore[j] == adap_id ||
|
||||
address_data->ignore[j] == ANY_I2C_BUS)
|
||||
&& address_data->ignore[j + 1]
|
||||
== address_data->normal_i2c[i]) {
|
||||
dev_dbg(&adapter->dev, "found ignore "
|
||||
"parameter for adapter %d, "
|
||||
"addr 0x%02x\n", adap_id,
|
||||
address_data->ignore[j + 1]);
|
||||
ignore = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ignore)
|
||||
continue;
|
||||
|
||||
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
|
||||
"addr 0x%02x\n", adap_id,
|
||||
address_data->normal_i2c[i]);
|
||||
temp_client->addr = address_data->normal_i2c[i];
|
||||
err = i2c_detect_address(temp_client, -1, driver);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
exit_free:
|
||||
kfree(temp_client);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct i2c_client *
|
||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
|
@ -1295,29 +1544,38 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
|
|||
if (rpec != cpec) {
|
||||
pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
|
||||
rpec, cpec);
|
||||
return -1;
|
||||
return -EBADMSG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
|
||||
{
|
||||
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
value,0,I2C_SMBUS_QUICK,NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_write_quick);
|
||||
|
||||
/**
|
||||
* i2c_smbus_read_byte - SMBus "receive byte" protocol
|
||||
* @client: Handle to slave device
|
||||
*
|
||||
* This executes the SMBus "receive byte" protocol, returning negative errno
|
||||
* else the byte received from the device.
|
||||
*/
|
||||
s32 i2c_smbus_read_byte(struct i2c_client *client)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
|
||||
return -1;
|
||||
else
|
||||
return data.byte;
|
||||
int status;
|
||||
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, 0,
|
||||
I2C_SMBUS_BYTE, &data);
|
||||
return (status < 0) ? status : data.byte;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_read_byte);
|
||||
|
||||
/**
|
||||
* i2c_smbus_write_byte - SMBus "send byte" protocol
|
||||
* @client: Handle to slave device
|
||||
* @value: Byte to be sent
|
||||
*
|
||||
* This executes the SMBus "send byte" protocol, returning negative errno
|
||||
* else zero on success.
|
||||
*/
|
||||
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
|
||||
{
|
||||
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
|
@ -1325,17 +1583,35 @@ s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_write_byte);
|
||||
|
||||
/**
|
||||
* i2c_smbus_read_byte_data - SMBus "read byte" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
*
|
||||
* This executes the SMBus "read byte" protocol, returning negative errno
|
||||
* else a data byte received from the device.
|
||||
*/
|
||||
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
|
||||
return -1;
|
||||
else
|
||||
return data.byte;
|
||||
int status;
|
||||
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
return (status < 0) ? status : data.byte;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_read_byte_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_write_byte_data - SMBus "write byte" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
* @value: Byte being written
|
||||
*
|
||||
* This executes the SMBus "write byte" protocol, returning negative errno
|
||||
* else zero on success.
|
||||
*/
|
||||
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
|
@ -1346,17 +1622,35 @@ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_write_byte_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_read_word_data - SMBus "read word" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
*
|
||||
* This executes the SMBus "read word" protocol, returning negative errno
|
||||
* else a 16-bit unsigned "word" received from the device.
|
||||
*/
|
||||
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
|
||||
return -1;
|
||||
else
|
||||
return data.word;
|
||||
int status;
|
||||
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
return (status < 0) ? status : data.word;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_read_word_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_write_word_data - SMBus "write word" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
* @value: 16-bit "word" being written
|
||||
*
|
||||
* This executes the SMBus "write word" protocol, returning negative errno
|
||||
* else zero on success.
|
||||
*/
|
||||
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
|
@ -1368,15 +1662,14 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
|
|||
EXPORT_SYMBOL(i2c_smbus_write_word_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_read_block_data - SMBus block read request
|
||||
* i2c_smbus_read_block_data - SMBus "block read" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Command byte issued to let the slave know what data should
|
||||
* be returned
|
||||
* @command: Byte interpreted by slave
|
||||
* @values: Byte array into which data will be read; big enough to hold
|
||||
* the data returned by the slave. SMBus allows at most 32 bytes.
|
||||
*
|
||||
* Returns the number of bytes read in the slave's response, else a
|
||||
* negative number to indicate some kind of error.
|
||||
* This executes the SMBus "block read" protocol, returning negative errno
|
||||
* else the number of data bytes in the slave's response.
|
||||
*
|
||||
* Note that using this function requires that the client's adapter support
|
||||
* the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers
|
||||
|
@ -1387,17 +1680,29 @@ s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
|
|||
u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int status;
|
||||
|
||||
if (i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data))
|
||||
return -1;
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
memcpy(values, &data.block[1], data.block[0]);
|
||||
return data.block[0];
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_read_block_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_write_block_data - SMBus "block write" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
* @length: Size of data block; SMBus allows at most 32 bytes
|
||||
* @values: Byte array which will be written.
|
||||
*
|
||||
* This executes the SMBus "block write" protocol, returning negative errno
|
||||
* else zero on success.
|
||||
*/
|
||||
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
|
||||
u8 length, const u8 *values)
|
||||
{
|
||||
|
@ -1418,14 +1723,16 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
|
|||
u8 length, u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int status;
|
||||
|
||||
if (length > I2C_SMBUS_BLOCK_MAX)
|
||||
length = I2C_SMBUS_BLOCK_MAX;
|
||||
data.block[0] = length;
|
||||
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
|
||||
I2C_SMBUS_READ,command,
|
||||
I2C_SMBUS_I2C_BLOCK_DATA,&data))
|
||||
return -1;
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_READ, command,
|
||||
I2C_SMBUS_I2C_BLOCK_DATA, &data);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
memcpy(values, &data.block[1], data.block[0]);
|
||||
return data.block[0];
|
||||
|
@ -1466,6 +1773,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
};
|
||||
int i;
|
||||
u8 partial_pec = 0;
|
||||
int status;
|
||||
|
||||
msgbuf0[0] = command;
|
||||
switch(size) {
|
||||
|
@ -1515,10 +1823,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
} else {
|
||||
msg[0].len = data->block[0] + 2;
|
||||
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
|
||||
dev_err(&adapter->dev, "smbus_access called with "
|
||||
"invalid block write size (%d)\n",
|
||||
data->block[0]);
|
||||
return -1;
|
||||
dev_err(&adapter->dev,
|
||||
"Invalid block write size %d\n",
|
||||
data->block[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 1; i < msg[0].len; i++)
|
||||
msgbuf0[i] = data->block[i-1];
|
||||
|
@ -1528,10 +1836,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
num = 2; /* Another special case */
|
||||
read_write = I2C_SMBUS_READ;
|
||||
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
|
||||
dev_err(&adapter->dev, "%s called with invalid "
|
||||
"block proc call size (%d)\n", __func__,
|
||||
dev_err(&adapter->dev,
|
||||
"Invalid block write size %d\n",
|
||||
data->block[0]);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
msg[0].len = data->block[0] + 2;
|
||||
for (i = 1; i < msg[0].len; i++)
|
||||
|
@ -1546,19 +1854,18 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
} else {
|
||||
msg[0].len = data->block[0] + 1;
|
||||
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
|
||||
dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
|
||||
"invalid block write size (%d)\n",
|
||||
data->block[0]);
|
||||
return -1;
|
||||
dev_err(&adapter->dev,
|
||||
"Invalid block write size %d\n",
|
||||
data->block[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 1; i <= data->block[0]; i++)
|
||||
msgbuf0[i] = data->block[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n",
|
||||
size);
|
||||
return -1;
|
||||
dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
|
||||
|
@ -1576,13 +1883,15 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
msg[num-1].len++;
|
||||
}
|
||||
|
||||
if (i2c_transfer(adapter, msg, num) < 0)
|
||||
return -1;
|
||||
status = i2c_transfer(adapter, msg, num);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* Check PEC if last message is a read */
|
||||
if (i && (msg[num-1].flags & I2C_M_RD)) {
|
||||
if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)
|
||||
return -1;
|
||||
status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_READ)
|
||||
|
@ -1610,9 +1919,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* i2c_smbus_xfer - execute SMBus protocol operations
|
||||
* @adapter: Handle to I2C bus
|
||||
* @addr: Address of SMBus slave on that bus
|
||||
* @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
|
||||
* @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
|
||||
* @command: Byte interpreted by slave, for protocols which use such bytes
|
||||
* @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
|
||||
* @data: Data to be read or written
|
||||
*
|
||||
* This executes an SMBus protocol operation, and returns a negative
|
||||
* errno code else zero on success.
|
||||
*/
|
||||
s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
|
||||
char read_write, u8 command, int size,
|
||||
char read_write, u8 command, int protocol,
|
||||
union i2c_smbus_data * data)
|
||||
{
|
||||
s32 res;
|
||||
|
@ -1622,11 +1943,11 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
|
|||
if (adapter->algo->smbus_xfer) {
|
||||
mutex_lock(&adapter->bus_lock);
|
||||
res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
|
||||
command,size,data);
|
||||
command, protocol, data);
|
||||
mutex_unlock(&adapter->bus_lock);
|
||||
} else
|
||||
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
|
||||
command,size,data);
|
||||
command, protocol, data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -367,8 +367,7 @@ static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
|
|||
return res;
|
||||
}
|
||||
|
||||
static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct i2c_client *client = (struct i2c_client *)file->private_data;
|
||||
unsigned long funcs;
|
||||
|
@ -497,7 +496,7 @@ static const struct file_operations i2cdev_fops = {
|
|||
.llseek = no_llseek,
|
||||
.read = i2cdev_read,
|
||||
.write = i2cdev_write,
|
||||
.ioctl = i2cdev_ioctl,
|
||||
.unlocked_ioctl = i2cdev_ioctl,
|
||||
.open = i2cdev_open,
|
||||
.release = i2cdev_release,
|
||||
};
|
||||
|
@ -559,19 +558,12 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i2cdev_detach_client(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver i2cdev_driver = {
|
||||
.driver = {
|
||||
.name = "dev_driver",
|
||||
},
|
||||
.id = I2C_DRIVERID_I2CDEV,
|
||||
.attach_adapter = i2cdev_attach_adapter,
|
||||
.detach_adapter = i2cdev_detach_adapter,
|
||||
.detach_client = i2cdev_detach_client,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
|
|
@ -106,6 +106,7 @@ unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
|
|||
algo_data->setsda(algo_data->data, 1);
|
||||
algo_data->setscl(algo_data->data, 1);
|
||||
|
||||
adapter->class |= I2C_CLASS_DDC;
|
||||
return edid;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,8 @@ static int intelfb_gpio_getsda(void *data)
|
|||
|
||||
static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
|
||||
struct intelfb_i2c_chan *chan,
|
||||
const u32 reg, const char *name)
|
||||
const u32 reg, const char *name,
|
||||
int class)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -108,6 +109,7 @@ static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
|
|||
chan->reg = reg;
|
||||
snprintf(chan->adapter.name, sizeof(chan->adapter.name),
|
||||
"intelfb %s", name);
|
||||
chan->adapter.class = class;
|
||||
chan->adapter.owner = THIS_MODULE;
|
||||
chan->adapter.id = I2C_HW_B_INTELFB;
|
||||
chan->adapter.algo_data = &chan->algo;
|
||||
|
@ -145,7 +147,7 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
|
|||
|
||||
/* setup the DDC bus for analog output */
|
||||
intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA,
|
||||
"CRTDDC_A");
|
||||
"CRTDDC_A", I2C_CLASS_DDC);
|
||||
i++;
|
||||
|
||||
/* need to add the output busses for each device
|
||||
|
@ -159,9 +161,9 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
|
|||
case INTEL_865G:
|
||||
dinfo->output[i].type = INTELFB_OUTPUT_DVO;
|
||||
intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus,
|
||||
GPIOD, "DVODDC_D");
|
||||
GPIOD, "DVODDC_D", I2C_CLASS_DDC);
|
||||
intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
|
||||
GPIOE, "DVOI2C_E");
|
||||
GPIOE, "DVOI2C_E", 0);
|
||||
i++;
|
||||
break;
|
||||
case INTEL_915G:
|
||||
|
@ -174,7 +176,7 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
|
|||
/* SDVO ports have a single control bus - 2 devices */
|
||||
dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
|
||||
intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
|
||||
GPIOE, "SDVOCTRL_E");
|
||||
GPIOE, "SDVOCTRL_E", 0);
|
||||
/* TODO: initialize the SDVO */
|
||||
/* I830SDVOInit(pScrn, i, DVOB); */
|
||||
i++;
|
||||
|
|
|
@ -104,7 +104,9 @@ static struct i2c_algo_bit_data matrox_i2c_algo_template =
|
|||
};
|
||||
|
||||
static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
|
||||
unsigned int data, unsigned int clock, const char* name) {
|
||||
unsigned int data, unsigned int clock, const char *name,
|
||||
int class)
|
||||
{
|
||||
int err;
|
||||
|
||||
b->minfo = minfo;
|
||||
|
@ -114,6 +116,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
|
|||
snprintf(b->adapter.name, sizeof(b->adapter.name), name,
|
||||
minfo->fbcon.node);
|
||||
i2c_set_adapdata(&b->adapter, b);
|
||||
b->adapter.class = class;
|
||||
b->adapter.algo_data = &b->bac;
|
||||
b->adapter.dev.parent = &ACCESS_FBINFO(pcidev)->dev;
|
||||
b->bac = matrox_i2c_algo_template;
|
||||
|
@ -159,22 +162,29 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
|
|||
switch (ACCESS_FBINFO(chip)) {
|
||||
case MGA_2064:
|
||||
case MGA_2164:
|
||||
err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0");
|
||||
err = i2c_bus_reg(&m2info->ddc1, minfo,
|
||||
DDC1B_DATA, DDC1B_CLK,
|
||||
"DDC:fb%u #0", I2C_CLASS_DDC);
|
||||
break;
|
||||
default:
|
||||
err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0");
|
||||
err = i2c_bus_reg(&m2info->ddc1, minfo,
|
||||
DDC1_DATA, DDC1_CLK,
|
||||
"DDC:fb%u #0", I2C_CLASS_DDC);
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
goto fail_ddc1;
|
||||
if (ACCESS_FBINFO(devflags.dualhead)) {
|
||||
err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1");
|
||||
err = i2c_bus_reg(&m2info->ddc2, minfo,
|
||||
DDC2_DATA, DDC2_CLK,
|
||||
"DDC:fb%u #1", I2C_CLASS_DDC);
|
||||
if (err == -ENODEV) {
|
||||
printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
|
||||
} else if (err)
|
||||
printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
|
||||
/* Register maven bus even on G450/G550 */
|
||||
err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u");
|
||||
err = i2c_bus_reg(&m2info->maven, minfo,
|
||||
MAT_DATA, MAT_CLK, "MAVEN:fb%u", 0);
|
||||
if (err)
|
||||
printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
|
||||
}
|
||||
|
|
|
@ -33,9 +33,11 @@ struct i2c_algo_pcf_data {
|
|||
int (*getclock) (void *data);
|
||||
void (*waitforpin) (void);
|
||||
|
||||
/* local settings */
|
||||
int udelay;
|
||||
int timeout;
|
||||
/* Multi-master lost arbitration back-off delay (msecs)
|
||||
* This should be set by the bus adapter or knowledgable client
|
||||
* if bus is multi-mastered, else zero
|
||||
*/
|
||||
unsigned long lab_mdelay;
|
||||
};
|
||||
|
||||
int i2c_pcf_add_bus(struct i2c_adapter *);
|
||||
|
|
|
@ -91,8 +91,6 @@
|
|||
#define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */
|
||||
#define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */
|
||||
|
||||
#define I2C_DRIVERID_I2CDEV 900
|
||||
|
||||
#define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */
|
||||
|
||||
/*
|
||||
|
@ -111,7 +109,6 @@
|
|||
#define I2C_HW_B_RIVA 0x010010 /* Riva based graphics cards */
|
||||
#define I2C_HW_B_IOC 0x010011 /* IOC bit-wiggling */
|
||||
#define I2C_HW_B_IXP2000 0x010016 /* GPIO on IXP2000 systems */
|
||||
#define I2C_HW_B_S3VIA 0x010018 /* S3Via ProSavage adapter */
|
||||
#define I2C_HW_B_ZR36067 0x010019 /* Zoran-36057/36067 based boards */
|
||||
#define I2C_HW_B_PCILYNX 0x01001a /* TI PCILynx I2C adapter */
|
||||
#define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <linux/sched.h> /* for completion */
|
||||
#include <linux/mutex.h>
|
||||
|
||||
extern struct bus_type i2c_bus_type;
|
||||
|
||||
/* --- General options ------------------------------------------------ */
|
||||
|
||||
struct i2c_msg;
|
||||
|
@ -43,6 +45,7 @@ struct i2c_adapter;
|
|||
struct i2c_client;
|
||||
struct i2c_driver;
|
||||
union i2c_smbus_data;
|
||||
struct i2c_board_info;
|
||||
|
||||
/*
|
||||
* The master routines are the ones normally used to transmit data to devices
|
||||
|
@ -69,9 +72,8 @@ extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr,
|
|||
union i2c_smbus_data * data);
|
||||
|
||||
/* Now follow the 'nice' access routines. These also document the calling
|
||||
conventions of smbus_access. */
|
||||
conventions of i2c_smbus_xfer. */
|
||||
|
||||
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_read_byte(struct i2c_client * client);
|
||||
extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command);
|
||||
|
@ -93,15 +95,33 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
|
|||
u8 command, u8 length,
|
||||
const u8 *values);
|
||||
|
||||
/*
|
||||
* A driver is capable of handling one or more physical devices present on
|
||||
* I2C adapters. This information is used to inform the driver of adapter
|
||||
* events.
|
||||
/**
|
||||
* struct i2c_driver - represent an I2C device driver
|
||||
* @class: What kind of i2c device we instantiate (for detect)
|
||||
* @detect: Callback for device detection
|
||||
* @address_data: The I2C addresses to probe, ignore or force (for detect)
|
||||
* @clients: List of detected clients we created (for i2c-core use only)
|
||||
*
|
||||
* The driver.owner field should be set to the module owner of this driver.
|
||||
* The driver.name field should be set to the name of this driver.
|
||||
*
|
||||
* For automatic device detection, both @detect and @address_data must
|
||||
* be defined. @class should also be set, otherwise only devices forced
|
||||
* with module parameters will be created. The detect function must
|
||||
* fill at least the name field of the i2c_board_info structure it is
|
||||
* handed upon successful detection, and possibly also the flags field.
|
||||
*
|
||||
* If @detect is missing, the driver will still work fine for enumerated
|
||||
* devices. Detected devices simply won't be supported. This is expected
|
||||
* for the many I2C/SMBus devices which can't be detected reliably, and
|
||||
* the ones which can always be enumerated in practice.
|
||||
*
|
||||
* The i2c_client structure which is handed to the @detect callback is
|
||||
* not a real i2c_client. It is initialized just enough so that you can
|
||||
* call i2c_smbus_read_byte_data and friends on it. Don't do anything
|
||||
* else with it. In particular, calling dev_dbg and friends on it is
|
||||
* not allowed.
|
||||
*/
|
||||
|
||||
struct i2c_driver {
|
||||
int id;
|
||||
unsigned int class;
|
||||
|
@ -141,6 +161,11 @@ struct i2c_driver {
|
|||
|
||||
struct device_driver driver;
|
||||
const struct i2c_device_id *id_table;
|
||||
|
||||
/* Device detection callback for automatic device creation */
|
||||
int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);
|
||||
const struct i2c_client_address_data *address_data;
|
||||
struct list_head clients;
|
||||
};
|
||||
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
|
||||
|
||||
|
@ -156,6 +181,7 @@ struct i2c_driver {
|
|||
* @dev: Driver model device node for the slave.
|
||||
* @irq: indicates the IRQ generated by this device (if any)
|
||||
* @list: list of active/busy clients (DEPRECATED)
|
||||
* @detected: member of an i2c_driver.clients list
|
||||
* @released: used to synchronize client releases & detaches and references
|
||||
*
|
||||
* An i2c_client identifies a single device (i.e. chip) connected to an
|
||||
|
@ -173,6 +199,7 @@ struct i2c_client {
|
|||
struct device dev; /* the device structure */
|
||||
int irq; /* irq issued by device */
|
||||
struct list_head list; /* DEPRECATED */
|
||||
struct list_head detected;
|
||||
struct completion released;
|
||||
};
|
||||
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
|
||||
|
@ -350,10 +377,11 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
|
|||
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
|
||||
#define I2C_CLASS_TV_ANALOG (1<<1) /* bttv + friends */
|
||||
#define I2C_CLASS_TV_DIGITAL (1<<2) /* dvb cards */
|
||||
#define I2C_CLASS_DDC (1<<3) /* i2c-matroxfb ? */
|
||||
#define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */
|
||||
#define I2C_CLASS_CAM_ANALOG (1<<4) /* camera with analog CCD */
|
||||
#define I2C_CLASS_CAM_DIGITAL (1<<5) /* most webcams */
|
||||
#define I2C_CLASS_SOUND (1<<6) /* sound devices */
|
||||
#define I2C_CLASS_SPD (1<<7) /* SPD EEPROMs and similar */
|
||||
#define I2C_CLASS_ALL (UINT_MAX) /* all of the above */
|
||||
|
||||
/* i2c_client_address_data is the struct for holding default client
|
||||
|
@ -537,7 +565,7 @@ union i2c_smbus_data {
|
|||
/* and one more for user-space compatibility */
|
||||
};
|
||||
|
||||
/* smbus_access read or write markers */
|
||||
/* i2c_smbus_xfer read or write markers */
|
||||
#define I2C_SMBUS_READ 1
|
||||
#define I2C_SMBUS_WRITE 0
|
||||
|
||||
|
|
28
include/linux/i2c/at24.h
Normal file
28
include/linux/i2c/at24.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef _LINUX_AT24_H
|
||||
#define _LINUX_AT24_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* As seen through Linux I2C, differences between the most common types of I2C
|
||||
* memory include:
|
||||
* - How much memory is available (usually specified in bit)?
|
||||
* - What write page size does it support?
|
||||
* - Special flags (16 bit addresses, read_only, world readable...)?
|
||||
*
|
||||
* If you set up a custom eeprom type, please double-check the parameters.
|
||||
* Especially page_size needs extra care, as you risk data loss if your value
|
||||
* is bigger than what the chip actually supports!
|
||||
*/
|
||||
|
||||
struct at24_platform_data {
|
||||
u32 byte_len; /* size (sum of all addr) */
|
||||
u16 page_size; /* for writes */
|
||||
u8 flags;
|
||||
#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */
|
||||
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
|
||||
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
|
||||
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
|
||||
};
|
||||
|
||||
#endif /* _LINUX_AT24_H */
|
Loading…
Reference in a new issue