Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6

* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: (26 commits)
  i2c-rpx: Remove
  i2c-mpc: work around missing-9th-clock-pulse bug
  i2c: New PMC MSP71xx TWI bus driver
  i2c-savage4: Delete many unused defines
  i2c/tsl2550: Speed up initialization
  i2c: New bus driver for the TAOS evaluation modules
  i2c-i801: Use the internal 32-byte buffer on ICH4+
  i2c-i801: Various cleanups
  i2c: Add support for the TSL2550
  i2c-pxa: Support new-style I2C drivers
  i2c-gpio: Make some internal functions static
  i2c-gpio: Add support for new-style clients
  i2c-iop3xx: Switch to static adapter numbering
  i2c-sis5595: Resolve resource conflict with sis5595
  matroxfb: Clean-up i2c header inclusions
  i2c-nforce2: Add support for SMBus block transactions
  i2c-mpc: Use i2c_add_numbered_adapter
  i2c-mv64xxx: Use i2c_add_numbered_adapter
  i2c-piix4: Add support for the ATI SB700
  i2c: New DS1682 chip driver
  ...
This commit is contained in:
Linus Torvalds 2007-07-12 13:25:00 -07:00
Родитель c397368232 0a85e9a271
Коммит 068345f4a8
42 изменённых файлов: 2222 добавлений и 330 удалений

Просмотреть файл

@ -643,6 +643,60 @@ X!Idrivers/video/console/fonts.c
!Edrivers/spi/spi.c !Edrivers/spi/spi.c
</chapter> </chapter>
<chapter id="i2c">
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
<para>
I<superscript>2</superscript>C (or without fancy typography, "I2C")
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
widely used where low data rate communications suffice.
Since it's also a licensed trademark, some vendors use another
name (such as "Two-Wire Interface", TWI) for the same bus.
I2C only needs two signals (SCL for clock, SDA for data), conserving
board real estate and minimizing signal quality issues.
Most I2C devices use seven bit addresses, and bus speeds of up
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
found wide use.
I2C is a multi-master bus; open drain signaling is used to
arbitrate between masters, as well as to handshake and to
synchronize clocks from slower clients.
</para>
<para>
The Linux I2C programming interfaces support only the master
side of bus interactions, not the slave side.
The programming interface is structured around two kinds of driver,
and two kinds of device.
An I2C "Adapter Driver" abstracts the controller hardware; it binds
to a physical device (perhaps a PCI device or platform_device) and
exposes a <structname>struct i2c_adapter</structname> representing
each I2C bus segment it manages.
On each I2C bus segment will be I2C devices represented by a
<structname>struct i2c_client</structname>. Those devices will
be bound to a <structname>struct i2c_driver</structname>,
which should follow the standard Linux driver model.
(At this writing, a legacy model is more widely used.)
There are functions to perform various I2C protocol operations; at
this writing all such functions are usable only from task context.
</para>
<para>
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
systems are also I2C conformant. The electrical constraints are
tighter for SMBus, and it standardizes particular protocol messages
and idioms. Controllers that support I2C can also support most
SMBus operations, but SMBus controllers don't support all the protocol
options that an I2C controller will.
There are functions to perform various SMBus protocol operations,
either using I2C primitives or by issuing SMBus commands to
i2c_adapter devices which don't support those I2C operations.
</para>
!Iinclude/linux/i2c.h
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
!Edrivers/i2c/i2c-core.c
</chapter>
<chapter id="splice"> <chapter id="splice">
<title>splice API</title> <title>splice API</title>
<para>) <para>)
@ -654,4 +708,5 @@ X!Idrivers/video/console/fonts.c
!Ffs/splice.c !Ffs/splice.c
</chapter> </chapter>
</book> </book>

Просмотреть файл

@ -330,3 +330,10 @@ Who: Tejun Heo <htejun@gmail.com>
--------------------------- ---------------------------
What: Legacy RTC drivers (under drivers/i2c/chips)
When: November 2007
Why: Obsolete. We have a RTC subsystem with better drivers.
Who: Jean Delvare <khali@linux-fr.org>
---------------------------

Просмотреть файл

@ -5,8 +5,8 @@ Supported adapters:
'810' and '810E' chipsets) '810' and '810E' chipsets)
* Intel 82801BA (ICH2 - part of the '815E' chipset) * Intel 82801BA (ICH2 - part of the '815E' chipset)
* Intel 82801CA/CAM (ICH3) * Intel 82801CA/CAM (ICH3)
* Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported) * Intel 82801DB (ICH4) (HW PEC supported)
* Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported) * Intel 82801EB/ER (ICH5) (HW PEC supported)
* Intel 6300ESB * Intel 6300ESB
* Intel 82801FB/FR/FW/FRW (ICH6) * Intel 82801FB/FR/FW/FRW (ICH6)
* Intel 82801G (ICH7) * Intel 82801G (ICH7)

Просмотреть файл

@ -6,7 +6,7 @@ Supported adapters:
Datasheet: Publicly available at the Intel website Datasheet: Publicly available at the Intel website
* ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
Datasheet: Only available via NDA from ServerWorks Datasheet: Only available via NDA from ServerWorks
* ATI IXP200, IXP300, IXP400 and SB600 southbridges * ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges
Datasheet: Not publicly available Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com Datasheet: Publicly available at the SMSC website http://www.smsc.com

Просмотреть файл

@ -0,0 +1,46 @@
Kernel driver i2c-taos-evm
Author: Jean Delvare <khali@linux-fr.org>
This is a driver for the evaluation modules for TAOS I2C/SMBus chips.
The modules include an SMBus master with limited capabilities, which can
be controlled over the serial port. Virtually all evaluation modules
are supported, but a few lines of code need to be added for each new
module to instantiate the right I2C chip on the bus. Obviously, a driver
for the chip in question is also needed.
Currently supported devices are:
* TAOS TSL2550 EVM
For addtional information on TAOS products, please see
http://www.taosinc.com/
Using this driver
-----------------
In order to use this driver, you'll need the serport driver, and the
inputattach tool, which is part of the input-utils package. The following
commands will tell the kernel that you have a TAOS EVM on the first
serial port:
# modprobe serport
# inputattach --taos-evm /dev/ttyS0
Technical details
-----------------
Only 4 SMBus transaction types are supported by the TAOS evaluation
modules:
* Receive Byte
* Send Byte
* Read Byte
* Write Byte
The communication protocol is text-based and pretty simple. It is
described in a PDF document on the CD which comes with the evaluation
module. The communication is rather slow, because the serial port has
to operate at 1200 bps. However, I don't think this is a big concern in
practice, as these modules are meant for evaluation and testing only.

Просмотреть файл

@ -99,7 +99,7 @@ And then read the data
or or
count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer); count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
The block read should read 16 bytes. The block read should read 16 bytes.
0x84 is the block read command. 0x84 is the block read command.

Просмотреть файл

@ -1,38 +0,0 @@
Kernel driver x1205
===================
Supported chips:
* Xicor X1205 RTC
Prefix: 'x1205'
Addresses scanned: none
Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
Authors:
Karen Spearel <kas11@tampabay.rr.com>,
Alessandro Zummo <a.zummo@towertech.it>
Description
-----------
This module aims to provide complete access to the Xicor X1205 RTC.
Recently Xicor has merged with Intersil, but the chip is
still sold under the Xicor brand.
This chip is located at address 0x6f and uses a 2-byte register addressing.
Two bytes need to be written to read a single register, while most
other chips just require one and take the second one as the data
to be written. To prevent corrupting unknown chips, the user must
explicitely set the probe parameter.
example:
modprobe x1205 probe=0,0x6f
The module supports one more option, hctosys, which is used to set the
software clock from the x1205. On systems where the x1205 is the
only hardware rtc, this parameter could be used to achieve a correct
date/time earlier in the system boot sequence.
example:
modprobe x1205 probe=0,0x6f hctosys=1

Просмотреть файл

@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers
Algorithm drivers Algorithm drivers
----------------- -----------------
i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
i2c-algo-bit: A bit-banging algorithm i2c-algo-bit: A bit-banging algorithm
i2c-algo-pcf: A PCF 8584 style algorithm i2c-algo-pcf: A PCF 8584 style algorithm
i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT) i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
@ -81,6 +80,5 @@ i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatch
i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT) i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit) i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit)
i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit) i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit)

Просмотреть файл

@ -571,7 +571,7 @@ SMBus communication
u8 command, u8 length, u8 command, u8 length,
u8 *values); u8 *values);
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
u8 command, u8 *values); u8 command, u8 length, u8 *values);
These ones were removed in Linux 2.6.10 because they had no users, but could These ones were removed in Linux 2.6.10 because they had no users, but could
be added back later if needed: be added back later if needed:

Просмотреть файл

@ -34,10 +34,6 @@ config I2C_ALGOPCA
This support is also available as a module. If so, the module This support is also available as a module. If so, the module
will be called i2c-algo-pca. will be called i2c-algo-pca.
config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
depends on 8xx
config I2C_ALGO_SGI config I2C_ALGO_SGI
tristate "I2C SGI interfaces" tristate "I2C SGI interfaces"
depends on SGI_IP22 || SGI_IP32 || X86_VISWS depends on SGI_IP22 || SGI_IP32 || X86_VISWS

Просмотреть файл

@ -207,6 +207,7 @@ config I2C_PIIX4
ATI IXP300 ATI IXP300
ATI IXP400 ATI IXP400
ATI SB600 ATI SB600
ATI SB700
Serverworks OSB4 Serverworks OSB4
Serverworks CSB5 Serverworks CSB5
Serverworks CSB6 Serverworks CSB6
@ -390,11 +391,6 @@ config I2C_PROSAVAGE
This support is also available as a module. If so, the module This support is also available as a module. If so, the module
will be called i2c-prosavage. will be called i2c-prosavage.
config I2C_RPXLITE
tristate "Embedded Planet RPX Lite/Classic support"
depends on RPXLITE || RPXCLASSIC
select I2C_ALGO8XX
config I2C_S3C2410 config I2C_S3C2410
tristate "S3C2410 I2C Driver" tristate "S3C2410 I2C Driver"
depends on ARCH_S3C2410 depends on ARCH_S3C2410
@ -512,6 +508,22 @@ config I2C_SIS96X
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-sis96x. 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 config I2C_STUB
tristate "I2C/SMBus Test Stub" tristate "I2C/SMBus Test Stub"
depends on EXPERIMENTAL && m depends on EXPERIMENTAL && m
@ -635,4 +647,13 @@ config I2C_PNX
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-pnx. will be called i2c-pnx.
config I2C_PMCMSP
tristate "PMC MSP I2C TWI Controller"
depends on PMC_MSP
help
This driver supports the PMC TWI controller on MSP devices.
This driver can also be built as module. If so, the module
will be called i2c-pmcmsp.
endmenu endmenu

Просмотреть файл

@ -32,10 +32,10 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.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_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.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_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o

Просмотреть файл

@ -63,14 +63,14 @@ static void i2c_gpio_setscl_val(void *data, int state)
gpio_set_value(pdata->scl_pin, state); gpio_set_value(pdata->scl_pin, state);
} }
int i2c_gpio_getsda(void *data) static int i2c_gpio_getsda(void *data)
{ {
struct i2c_gpio_platform_data *pdata = data; struct i2c_gpio_platform_data *pdata = data;
return gpio_get_value(pdata->sda_pin); return gpio_get_value(pdata->sda_pin);
} }
int i2c_gpio_getscl(void *data) static int i2c_gpio_getscl(void *data)
{ {
struct i2c_gpio_platform_data *pdata = data; struct i2c_gpio_platform_data *pdata = data;
@ -142,7 +142,13 @@ static int __init i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data; adap->algo_data = bit_data;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
ret = i2c_bit_add_bus(adap); /*
* If "dev->id" is negative we consider it as zero.
* The reason to do so is to avoid sysfs names that only make
* sense when there are multiple adapters.
*/
adap->nr = pdev->id >= 0 ? pdev->id : 0;
ret = i2c_bit_add_numbered_bus(adap);
if (ret) if (ret)
goto err_add_bus; goto err_add_bus;

Просмотреть файл

@ -22,12 +22,12 @@
/* /*
SUPPORTED DEVICES PCI ID SUPPORTED DEVICES PCI ID
82801AA 2413 82801AA 2413
82801AB 2423 82801AB 2423
82801BA 2443 82801BA 2443
82801CA/CAM 2483 82801CA/CAM 2483
82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) 82801DB 24C3 (HW PEC supported)
82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) 82801EB 24D3 (HW PEC supported)
6300ESB 25A4 6300ESB 25A4
ICH6 266A ICH6 266A
ICH7 27DA ICH7 27DA
@ -74,6 +74,13 @@
#define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_SMB_SMI_EN 2
#define SMBHSTCFG_I2C_EN 4 #define SMBHSTCFG_I2C_EN 4
/* Auxillary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2
/* kill bit for SMBHSTCNT */
#define SMBHSTCNT_KILL 2
/* Other settings */ /* Other settings */
#define MAX_TIMEOUT 100 #define MAX_TIMEOUT 100
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
@ -91,10 +98,15 @@
#define I801_START 0x40 #define I801_START 0x40
#define I801_PEC_EN 0x80 /* ICH4 only */ #define I801_PEC_EN 0x80 /* ICH4 only */
/* I801 Hosts Status register bits */
static int i801_transaction(void); #define SMBHSTSTS_BYTE_DONE 0x80
static int i801_block_transaction(union i2c_smbus_data *data, char read_write, #define SMBHSTSTS_INUSE_STS 0x40
int command, int hwpec); #define SMBHSTSTS_SMBALERT_STS 0x20
#define SMBHSTSTS_FAILED 0x10
#define SMBHSTSTS_BUS_ERR 0x08
#define SMBHSTSTS_DEV_ERR 0x04
#define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01
static unsigned long i801_smba; static unsigned long i801_smba;
static unsigned char i801_original_hstcfg; static unsigned char i801_original_hstcfg;
@ -102,7 +114,7 @@ static struct pci_driver i801_driver;
static struct pci_dev *I801_dev; static struct pci_dev *I801_dev;
static int isich4; static int isich4;
static int i801_transaction(void) static int i801_transaction(int xact)
{ {
int temp; int temp;
int result = 0; int result = 0;
@ -127,33 +139,40 @@ static int i801_transaction(void)
} }
} }
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); /* the current contents of SMBHSTCNT can be overwritten, since PEC,
* INTREN, SMBSCMD are passed in xact */
outb_p(xact | I801_START, SMBHSTCNT);
/* We will always wait for a fraction of a second! */ /* We will always wait for a fraction of a second! */
do { do {
msleep(1); msleep(1);
temp = inb_p(SMBHSTSTS); temp = inb_p(SMBHSTSTS);
} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); } while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */ /* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) { if (timeout >= MAX_TIMEOUT) {
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
result = -1; result = -1;
/* try to stop the current command */
dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
msleep(1);
outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
} }
if (temp & 0x10) { if (temp & SMBHSTSTS_FAILED) {
result = -1; result = -1;
dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
} }
if (temp & 0x08) { if (temp & SMBHSTSTS_BUS_ERR) {
result = -1; result = -1;
dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
"until next hard reset. (sorry!)\n"); "until next hard reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */ /* Clock stops and slave is stuck in mid-transmission */
} }
if (temp & 0x04) { if (temp & SMBHSTSTS_DEV_ERR) {
result = -1; result = -1;
dev_dbg(&I801_dev->dev, "Error: no response!\n"); dev_dbg(&I801_dev->dev, "Error: no response!\n");
} }
@ -172,44 +191,70 @@ static int i801_transaction(void)
return result; return result;
} }
/* All-inclusive block transaction function */ /* wait for INTR bit as advised by Intel */
static int i801_block_transaction(union i2c_smbus_data *data, char read_write, static void i801_wait_hwpec(void)
int command, int hwpec) {
int timeout = 0;
int temp;
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
} while ((!(temp & SMBHSTSTS_INTR))
&& (timeout++ < MAX_TIMEOUT));
if (timeout >= MAX_TIMEOUT) {
dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
}
outb_p(temp, SMBHSTSTS);
}
static int i801_block_transaction_by_block(union i2c_smbus_data *data,
char read_write, int hwpec)
{
int i, len;
inb_p(SMBHSTCNT); /* reset the data buffer index */
/* Use 32-byte buffer to process this transaction */
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
outb_p(len, SMBHSTDAT0);
for (i = 0; i < len; i++)
outb_p(data->block[i+1], SMBBLKDAT);
}
if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
I801_PEC_EN * hwpec))
return -1;
if (read_write == I2C_SMBUS_READ) {
len = inb_p(SMBHSTDAT0);
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
return -1;
data->block[0] = len;
for (i = 0; i < len; i++)
data->block[i + 1] = inb_p(SMBBLKDAT);
}
return 0;
}
static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
char read_write, int hwpec)
{ {
int i, len; int i, len;
int smbcmd; int smbcmd;
int temp; int temp;
int result = 0; int result = 0;
int timeout; int timeout;
unsigned char hostc, errmask; unsigned char errmask;
if (command == I2C_SMBUS_I2C_BLOCK_DATA) { len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
pci_write_config_byte(I801_dev, SMBHSTCFG,
hostc | SMBHSTCFG_I2C_EN);
} else {
dev_err(&I801_dev->dev,
"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
return -1;
}
}
if (read_write == I2C_SMBUS_WRITE) { if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
if (len < 1)
len = 1;
if (len > 32)
len = 32;
outb_p(len, SMBHSTDAT0); outb_p(len, SMBHSTDAT0);
outb_p(data->block[1], SMBBLKDAT); outb_p(data->block[1], SMBBLKDAT);
} else {
len = 32; /* max for reads */
}
if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
/* set 32 byte buffer */
} }
for (i = 1; i <= len; i++) { for (i = 1; i <= len; i++) {
@ -227,13 +272,13 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* Make sure the SMBus host is ready to start transmitting */ /* Make sure the SMBus host is ready to start transmitting */
temp = inb_p(SMBHSTSTS); temp = inb_p(SMBHSTSTS);
if (i == 1) { if (i == 1) {
/* Erronenous conditions before transaction: /* Erronenous conditions before transaction:
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
errmask=0x9f; errmask = 0x9f;
} else { } else {
/* Erronenous conditions during transaction: /* Erronenous conditions during transaction:
* Failed, Bus_Err, Dev_Err, Intr */ * Failed, Bus_Err, Dev_Err, Intr */
errmask=0x1e; errmask = 0x1e;
} }
if (temp & errmask) { if (temp & errmask) {
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
@ -242,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
dev_err(&I801_dev->dev, dev_err(&I801_dev->dev,
"Reset failed! (%02x)\n", temp); "Reset failed! (%02x)\n", temp);
result = -1; return -1;
goto END;
} }
if (i != 1) { if (i != 1)
/* if die in middle of block transaction, fail */ /* if die in middle of block transaction, fail */
result = -1; return -1;
goto END;
}
} }
if (i == 1) if (i == 1)
@ -261,33 +303,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
msleep(1); msleep(1);
temp = inb_p(SMBHSTSTS); temp = inb_p(SMBHSTSTS);
} }
while ((!(temp & 0x80)) while ((!(temp & SMBHSTSTS_BYTE_DONE))
&& (timeout++ < MAX_TIMEOUT)); && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */ /* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) { 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; result = -1;
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
} }
if (temp & 0x10) { if (temp & SMBHSTSTS_FAILED) {
result = -1; result = -1;
dev_dbg(&I801_dev->dev, dev_dbg(&I801_dev->dev,
"Error: Failed bus transaction\n"); "Error: Failed bus transaction\n");
} else if (temp & 0x08) { } else if (temp & SMBHSTSTS_BUS_ERR) {
result = -1; result = -1;
dev_err(&I801_dev->dev, "Bus collision!\n"); dev_err(&I801_dev->dev, "Bus collision!\n");
} else if (temp & 0x04) { } else if (temp & SMBHSTSTS_DEV_ERR) {
result = -1; result = -1;
dev_dbg(&I801_dev->dev, "Error: no response!\n"); dev_dbg(&I801_dev->dev, "Error: no response!\n");
} }
if (i == 1 && read_write == I2C_SMBUS_READ) { if (i == 1 && read_write == I2C_SMBUS_READ) {
len = inb_p(SMBHSTDAT0); len = inb_p(SMBHSTDAT0);
if (len < 1) if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
len = 1; return -1;
if (len > 32)
len = 32;
data->block[0] = len; data->block[0] = len;
} }
@ -310,25 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
if (result < 0) if (result < 0)
goto END; return result;
} }
return result;
}
if (hwpec) { static int i801_set_block_buffer_mode(void)
/* wait for INTR bit as advised by Intel */ {
timeout = 0; outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
do { if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
msleep(1); return -1;
temp = inb_p(SMBHSTSTS); return 0;
} while ((!(temp & 0x02)) }
&& (timeout++ < MAX_TIMEOUT));
if (timeout >= MAX_TIMEOUT) { /* Block transaction function */
dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
int command, int hwpec)
{
int result = 0;
unsigned char hostc;
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
pci_write_config_byte(I801_dev, SMBHSTCFG,
hostc | SMBHSTCFG_I2C_EN);
} else {
dev_err(&I801_dev->dev,
"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
return -1;
} }
outb_p(temp, SMBHSTSTS);
} }
result = 0;
END: if (read_write == I2C_SMBUS_WRITE) {
if (data->block[0] < 1)
data->block[0] = 1;
if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
data->block[0] = I2C_SMBUS_BLOCK_MAX;
} else {
data->block[0] = 32; /* max for reads */
}
if (isich4 && i801_set_block_buffer_mode() == 0 )
result = i801_block_transaction_by_block(data, read_write,
hwpec);
else
result = i801_block_transaction_byte_by_byte(data, read_write,
hwpec);
if (result == 0 && hwpec)
i801_wait_hwpec();
if (command == I2C_SMBUS_I2C_BLOCK_DATA) { if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
/* restore saved configuration register value */ /* restore saved configuration register value */
pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
@ -393,19 +473,22 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
return -1; return -1;
} }
outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ if (hwpec) /* enable/disable hardware PEC */
outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
else
outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
if(block) if(block)
ret = i801_block_transaction(data, read_write, size, hwpec); ret = i801_block_transaction(data, read_write, size, hwpec);
else { else
outb_p(xact | ENABLE_INT9, SMBHSTCNT); ret = i801_transaction(xact | ENABLE_INT9);
ret = i801_transaction();
}
/* Some BIOSes don't like it when PEC is enabled at reboot or resume /* Some BIOSes don't like it when PEC is enabled at reboot or resume
time, so we forcibly disable it after every transaction. */ time, so we forcibly disable it after every transaction. Turn off
E32B for the same reason. */
if (hwpec) if (hwpec)
outb_p(0, SMBAUXCTL); outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
SMBAUXCTL);
if(block) if(block)
return ret; return ret;

Просмотреть файл

@ -491,6 +491,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
new_adapter->id = I2C_HW_IOP3XX; new_adapter->id = I2C_HW_IOP3XX;
new_adapter->owner = THIS_MODULE; new_adapter->owner = THIS_MODULE;
new_adapter->dev.parent = &pdev->dev; new_adapter->dev.parent = &pdev->dev;
new_adapter->nr = pdev->id;
/* /*
* Default values...should these come in from board code? * Default values...should these come in from board code?
@ -508,7 +509,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, new_adapter); platform_set_drvdata(pdev, new_adapter);
new_adapter->algo_data = adapter_data; new_adapter->algo_data = adapter_data;
i2c_add_adapter(new_adapter); i2c_add_numbered_adapter(new_adapter);
return 0; return 0;

Просмотреть файл

@ -74,6 +74,25 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
* the bus, because it wants to send ACK.
* Following sequence of enabling/disabling and sending start/stop generates
* the pulse, so it's all OK.
*/
static void mpc_i2c_fixup(struct mpc_i2c *i2c)
{
writeccr(i2c, 0);
udelay(30);
writeccr(i2c, CCR_MEN);
udelay(30);
writeccr(i2c, CCR_MSTA | CCR_MTX);
udelay(30);
writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
udelay(30);
writeccr(i2c, CCR_MEN);
udelay(30);
}
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
{ {
unsigned long orig_jiffies = jiffies; unsigned long orig_jiffies = jiffies;
@ -153,6 +172,7 @@ static void mpc_i2c_start(struct mpc_i2c *i2c)
static void mpc_i2c_stop(struct mpc_i2c *i2c) static void mpc_i2c_stop(struct mpc_i2c *i2c)
{ {
writeccr(i2c, CCR_MEN); writeccr(i2c, CCR_MEN);
writeccr(i2c, 0);
} }
static int mpc_write(struct mpc_i2c *i2c, int target, static int mpc_write(struct mpc_i2c *i2c, int target,
@ -245,6 +265,9 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
} }
if (time_after(jiffies, orig_jiffies + HZ)) { if (time_after(jiffies, orig_jiffies + HZ)) {
pr_debug("I2C: timeout\n"); pr_debug("I2C: timeout\n");
if (readb(i2c->base + MPC_I2C_SR) ==
(CSR_MCF | CSR_MBB | CSR_RXAK))
mpc_i2c_fixup(i2c);
return -EIO; return -EIO;
} }
schedule(); schedule();
@ -327,9 +350,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c); platform_set_drvdata(pdev, i2c);
i2c->adap = mpc_ops; i2c->adap = mpc_ops;
i2c->adap.nr = pdev->id;
i2c_set_adapdata(&i2c->adap, i2c); i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.parent = &pdev->dev;
if ((result = i2c_add_adapter(&i2c->adap)) < 0) { if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
goto fail_add; goto fail_add;
} }

Просмотреть файл

@ -527,6 +527,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->adapter.class = I2C_CLASS_HWMON; drv_data->adapter.class = I2C_CLASS_HWMON;
drv_data->adapter.timeout = pdata->timeout; drv_data->adapter.timeout = pdata->timeout;
drv_data->adapter.retries = pdata->retries; drv_data->adapter.retries = pdata->retries;
drv_data->adapter.nr = pd->id;
platform_set_drvdata(pd, drv_data); platform_set_drvdata(pd, drv_data);
i2c_set_adapdata(&drv_data->adapter, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data);
@ -539,7 +540,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->irq); drv_data->irq);
rc = -EINVAL; rc = -EINVAL;
goto exit_unmap_regs; goto exit_unmap_regs;
} else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev, dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
goto exit_free_irq; goto exit_free_irq;

Просмотреть файл

@ -61,6 +61,7 @@ struct nforce2_smbus {
struct i2c_adapter adapter; struct i2c_adapter adapter;
int base; int base;
int size; int size;
int blockops;
}; };
@ -80,6 +81,8 @@ struct nforce2_smbus {
#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
bytes */
#define NVIDIA_SMB_STS_DONE 0x80 #define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40 #define NVIDIA_SMB_STS_ALRM 0x40
@ -92,6 +95,7 @@ struct nforce2_smbus {
#define NVIDIA_SMB_PRTCL_BYTE 0x04 #define NVIDIA_SMB_PRTCL_BYTE 0x04
#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
#define NVIDIA_SMB_PRTCL_PEC 0x80 #define NVIDIA_SMB_PRTCL_PEC 0x80
static struct pci_driver nforce2_driver; static struct pci_driver nforce2_driver;
@ -103,6 +107,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
{ {
struct nforce2_smbus *smbus = adap->algo_data; struct nforce2_smbus *smbus = adap->algo_data;
unsigned char protocol, pec, temp; unsigned char protocol, pec, temp;
u8 len;
int i;
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
NVIDIA_SMB_PRTCL_WRITE; NVIDIA_SMB_PRTCL_WRITE;
@ -137,6 +143,25 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
break; break;
case I2C_SMBUS_BLOCK_DATA:
outb_p(command, NVIDIA_SMB_CMD);
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
dev_err(&adap->dev,
"Transaction failed "
"(requested block size: %d)\n",
len);
return -1;
}
outb_p(len, NVIDIA_SMB_BCNT);
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
outb_p(data->block[i + 1],
NVIDIA_SMB_DATA+i);
}
protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
break;
default: default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size); dev_err(&adap->dev, "Unsupported transaction %d\n", size);
return -1; return -1;
@ -174,6 +199,14 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_WORD_DATA:
data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
break; break;
case I2C_SMBUS_BLOCK_DATA:
len = inb_p(NVIDIA_SMB_BCNT);
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
for (i = 0; i < len; i++)
data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
data->block[0] = len;
break;
} }
return 0; return 0;
@ -184,7 +217,9 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
{ {
/* other functionality might be possible, but is not tested */ /* other functionality might be possible, but is not tested */
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
(((struct nforce2_smbus*)adapter->algo_data)->blockops ?
I2C_FUNC_SMBUS_BLOCK_DATA : 0);
} }
static struct i2c_algorithm smbus_algorithm = { static struct i2c_algorithm smbus_algorithm = {
@ -268,6 +303,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
return -ENOMEM; return -ENOMEM;
pci_set_drvdata(dev, smbuses); pci_set_drvdata(dev, smbuses);
switch(dev->device) {
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
smbuses[0].blockops = 1;
smbuses[1].blockops = 1;
}
/* SMBus adapter 1 */ /* SMBus adapter 1 */
res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
if (res1 < 0) { if (res1 < 0) {

Просмотреть файл

@ -23,7 +23,7 @@
Supports: Supports:
Intel PIIX4, 440MX Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000 Serverworks OSB4, CSB5, CSB6, HT-1000
ATI IXP200, IXP300, IXP400, SB600 ATI IXP200, IXP300, IXP400, SB600, SB700
SMSC Victory66 SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface. Note: we assume there can only be one device, with one SMBus interface.
@ -399,6 +399,8 @@ static struct pci_device_id piix4_ids[] = {
.driver_data = 0 }, .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS), { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
.driver_data = 0 }, .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
.driver_data = 0 }, .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),

Просмотреть файл

@ -0,0 +1,653 @@
/*
* Specific bus support for PMC-TWI compliant implementation on MSP71xx.
*
* Copyright 2005-2007 PMC-Sierra, Inc.
*
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* 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/init.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <asm/io.h>
#define DRV_NAME "pmcmsptwi"
#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
#define MSP_TWI_CFG_REG_OFFSET 0x08
#define MSP_TWI_CMD_REG_OFFSET 0x0c
#define MSP_TWI_ADD_REG_OFFSET 0x10
#define MSP_TWI_DAT_0_REG_OFFSET 0x14
#define MSP_TWI_DAT_1_REG_OFFSET 0x18
#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
#define MSP_TWI_BUSY_REG_OFFSET 0x24
#define MSP_TWI_INT_STS_DONE (1 << 0)
#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
#define MSP_TWI_INT_STS_BUSY (1 << 4)
#define MSP_TWI_INT_STS_ALL 0x1f
#define MSP_MAX_BYTES_PER_RW 8
#define MSP_MAX_POLL 5
#define MSP_POLL_DELAY 10
#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
/* IO Operation macros */
#define pmcmsptwi_readl __raw_readl
#define pmcmsptwi_writel __raw_writel
/* TWI command type */
enum pmcmsptwi_cmd_type {
MSP_TWI_CMD_WRITE = 0, /* Write only */
MSP_TWI_CMD_READ = 1, /* Read only */
MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
};
/* The possible results of the xferCmd */
enum pmcmsptwi_xfer_result {
MSP_TWI_XFER_OK = 0,
MSP_TWI_XFER_TIMEOUT,
MSP_TWI_XFER_BUSY,
MSP_TWI_XFER_DATA_COLLISION,
MSP_TWI_XFER_NO_RESPONSE,
MSP_TWI_XFER_LOST_ARBITRATION,
};
/* Corresponds to a PMCTWI clock configuration register */
struct pmcmsptwi_clock {
u8 filter; /* Bits 15:12, default = 0x03 */
u16 clock; /* Bits 9:0, default = 0x001f */
};
struct pmcmsptwi_clockcfg {
struct pmcmsptwi_clock standard; /* The standard/fast clock config */
struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
};
/* Corresponds to the main TWI configuration register */
struct pmcmsptwi_cfg {
u8 arbf; /* Bits 15:12, default=0x03 */
u8 nak; /* Bits 11:8, default=0x03 */
u8 add10; /* Bit 7, default=0x00 */
u8 mst_code; /* Bits 6:4, default=0x00 */
u8 arb; /* Bit 1, default=0x01 */
u8 highspeed; /* Bit 0, default=0x00 */
};
/* A single pmctwi command to issue */
struct pmcmsptwi_cmd {
u16 addr; /* The slave address (7 or 10 bits) */
enum pmcmsptwi_cmd_type type; /* The command type */
u8 write_len; /* Number of bytes in the write buffer */
u8 read_len; /* Number of bytes in the read buffer */
u8 *write_data; /* Buffer of characters to send */
u8 *read_data; /* Buffer to fill with incoming data */
};
/* The private data */
struct pmcmsptwi_data {
void __iomem *iobase; /* iomapped base for IO */
int irq; /* IRQ to use (0 disables) */
struct completion wait; /* Completion for xfer */
struct mutex lock; /* Used for threadsafeness */
enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
};
/* The default settings */
const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
.standard = {
.filter = 0x3,
.clock = 0x1f,
},
.highspeed = {
.filter = 0x3,
.clock = 0x1f,
},
};
const static struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
.arbf = 0x03,
.nak = 0x03,
.add10 = 0x00,
.mst_code = 0x00,
.arb = 0x01,
.highspeed = 0x00,
};
static struct pmcmsptwi_data pmcmsptwi_data;
static struct i2c_adapter pmcmsptwi_adapter;
/* inline helper functions */
static inline u32 pmcmsptwi_clock_to_reg(
const struct pmcmsptwi_clock *clock)
{
return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
}
static inline void pmcmsptwi_reg_to_clock(
u32 reg, struct pmcmsptwi_clock *clock)
{
clock->filter = (reg >> 12) & 0xf;
clock->clock = reg & 0x03ff;
}
static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
{
return ((cfg->arbf & 0xf) << 12) |
((cfg->nak & 0xf) << 8) |
((cfg->add10 & 0x1) << 7) |
((cfg->mst_code & 0x7) << 4) |
((cfg->arb & 0x1) << 1) |
(cfg->highspeed & 0x1);
}
static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
{
cfg->arbf = (reg >> 12) & 0xf;
cfg->nak = (reg >> 8) & 0xf;
cfg->add10 = (reg >> 7) & 0x1;
cfg->mst_code = (reg >> 4) & 0x7;
cfg->arb = (reg >> 1) & 0x1;
cfg->highspeed = reg & 0x1;
}
/*
* Sets the current clock configuration
*/
static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
mutex_unlock(&data->lock);
}
/*
* Gets the current TWI bus configuration
*/
static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
mutex_unlock(&data->lock);
}
/*
* Sets the current TWI bus configuration
*/
static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
data->iobase + MSP_TWI_CFG_REG_OFFSET);
mutex_unlock(&data->lock);
}
/*
* Parses the 'int_sts' register and returns a well-defined error code
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
{
if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Lost arbitration\n");
return MSP_TWI_XFER_LOST_ARBITRATION;
} else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: No response\n");
return MSP_TWI_XFER_NO_RESPONSE;
} else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Data collision\n");
return MSP_TWI_XFER_DATA_COLLISION;
} else if (reg & MSP_TWI_INT_STS_BUSY) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Bus busy\n");
return MSP_TWI_XFER_BUSY;
}
dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
return MSP_TWI_XFER_OK;
}
/*
* In interrupt mode, handle the interrupt.
* NOTE: Assumes data->lock is held.
*/
static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
{
struct pmcmsptwi_data *data = ptr;
u32 reason = pmcmsptwi_readl(data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
if (!(reason & MSP_TWI_INT_STS_DONE))
return IRQ_NONE;
data->last_result = pmcmsptwi_get_result(reason);
complete(&data->wait);
return IRQ_HANDLED;
}
/*
* Probe for and register the device and return 0 if there is one.
*/
static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
{
struct resource *res;
int rc = -ENODEV;
/* get the static platform resources */
res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pldev->dev, "IOMEM resource not found\n");
goto ret_err;
}
/* reserve the memory region */
if (!request_mem_region(res->start, res->end - res->start + 1,
pldev->name)) {
dev_err(&pldev->dev,
"Unable to get memory/io address region 0x%08x\n",
res->start);
rc = -EBUSY;
goto ret_err;
}
/* remap the memory */
pmcmsptwi_data.iobase = ioremap_nocache(res->start,
res->end - res->start + 1);
if (!pmcmsptwi_data.iobase) {
dev_err(&pldev->dev,
"Unable to ioremap address 0x%08x\n", res->start);
rc = -EIO;
goto ret_unreserve;
}
/* request the irq */
pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
if (pmcmsptwi_data.irq) {
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
pldev->name, &pmcmsptwi_data);
if (rc == 0) {
/*
* Enable 'DONE' interrupt only.
*
* If you enable all interrupts, you will get one on
* error and another when the operation completes.
* This way you only have to handle one interrupt,
* but you can still check all result flags.
*/
pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
pmcmsptwi_data.iobase +
MSP_TWI_INT_MSK_REG_OFFSET);
} else {
dev_warn(&pldev->dev,
"Could not assign TWI IRQ handler "
"to irq %d (continuing with poll)\n",
pmcmsptwi_data.irq);
pmcmsptwi_data.irq = 0;
}
}
init_completion(&pmcmsptwi_data.wait);
mutex_init(&pmcmsptwi_data.lock);
pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
pmcmsptwi_adapter.dev.parent = &pldev->dev;
platform_set_drvdata(pldev, &pmcmsptwi_adapter);
i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
rc = i2c_add_adapter(&pmcmsptwi_adapter);
if (rc) {
dev_err(&pldev->dev, "Unable to register I2C adapter\n");
goto ret_unmap;
}
return 0;
ret_unmap:
platform_set_drvdata(pldev, NULL);
if (pmcmsptwi_data.irq) {
pmcmsptwi_writel(0,
pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
}
iounmap(pmcmsptwi_data.iobase);
ret_unreserve:
release_mem_region(res->start, res->end - res->start + 1);
ret_err:
return rc;
}
/*
* Release the device and return 0 if there is one.
*/
static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
{
struct resource *res;
i2c_del_adapter(&pmcmsptwi_adapter);
platform_set_drvdata(pldev, NULL);
if (pmcmsptwi_data.irq) {
pmcmsptwi_writel(0,
pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
}
iounmap(pmcmsptwi_data.iobase);
res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
return 0;
}
/*
* Polls the 'busy' register until the command is complete.
* NOTE: Assumes data->lock is held.
*/
static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
{
int i;
for (i = 0; i < MSP_MAX_POLL; i++) {
u32 val = pmcmsptwi_readl(data->iobase +
MSP_TWI_BUSY_REG_OFFSET);
if (val == 0) {
u32 reason = pmcmsptwi_readl(data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
pmcmsptwi_writel(reason, data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
data->last_result = pmcmsptwi_get_result(reason);
return;
}
udelay(MSP_POLL_DELAY);
}
dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
data->last_result = MSP_TWI_XFER_TIMEOUT;
}
/*
* Do the transfer (low level):
* May use interrupt-driven or polling, depending on if an IRQ is
* presently registered.
* NOTE: Assumes data->lock is held.
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
u32 reg, struct pmcmsptwi_data *data)
{
dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
if (data->irq) {
unsigned long timeleft = wait_for_completion_timeout(
&data->wait, MSP_IRQ_TIMEOUT);
if (timeleft == 0) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: IRQ timeout\n");
complete(&data->wait);
data->last_result = MSP_TWI_XFER_TIMEOUT;
}
} else
pmcmsptwi_poll_complete(data);
return data->last_result;
}
/*
* Helper routine, converts 'pmctwi_cmd' struct to register format
*/
static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
{
return ((cmd->type & 0x3) << 8) |
(((cmd->write_len - 1) & 0x7) << 4) |
((cmd->read_len - 1) & 0x7);
}
/*
* Do the transfer (high level)
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
struct pmcmsptwi_cmd *cmd,
struct pmcmsptwi_data *data)
{
enum pmcmsptwi_xfer_result retval;
if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
(cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
(cmd->type == MSP_TWI_CMD_WRITE_READ &&
(cmd->read_len == 0 || cmd->write_len == 0))) {
dev_err(&pmcmsptwi_adapter.dev,
"%s: Cannot transfer less than 1 byte\n",
__FUNCTION__);
return -EINVAL;
}
if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
cmd->write_len > MSP_MAX_BYTES_PER_RW) {
dev_err(&pmcmsptwi_adapter.dev,
"%s: Cannot transfer more than %d bytes\n",
__FUNCTION__, MSP_MAX_BYTES_PER_RW);
return -EINVAL;
}
mutex_lock(&data->lock);
dev_dbg(&pmcmsptwi_adapter.dev,
"Setting address to 0x%04x\n", cmd->addr);
pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
if (cmd->type == MSP_TWI_CMD_WRITE ||
cmd->type == MSP_TWI_CMD_WRITE_READ) {
__be64 tmp = cpu_to_be64p((u64 *)cmd->write_data);
tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
if (cmd->write_len > 4)
pmcmsptwi_writel(tmp >> 32,
data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
}
retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
if (retval != MSP_TWI_XFER_OK)
goto xfer_err;
if (cmd->type == MSP_TWI_CMD_READ ||
cmd->type == MSP_TWI_CMD_WRITE_READ) {
int i;
u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
MSP_TWI_DAT_0_REG_OFFSET);
if (cmd->read_len > 4)
tmp |= (u64)pmcmsptwi_readl(data->iobase +
MSP_TWI_DAT_1_REG_OFFSET) << 32;
tmp &= rmsk;
dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
for (i = 0; i < cmd->read_len; i++)
cmd->read_data[i] = tmp >> i;
}
xfer_err:
mutex_unlock(&data->lock);
return retval;
}
/* -- Algorithm functions -- */
/*
* Sends an i2c command out on the adapter
*/
static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msg, int num)
{
struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
struct pmcmsptwi_cmd cmd;
struct pmcmsptwi_cfg oldcfg, newcfg;
int ret;
if (num > 2) {
dev_dbg(&adap->dev, "%d messages unsupported\n", num);
return -EINVAL;
} else if (num == 2) {
/* Check for a dual write-then-read command */
struct i2c_msg *nextmsg = msg + 1;
if (!(msg->flags & I2C_M_RD) &&
(nextmsg->flags & I2C_M_RD) &&
msg->addr == nextmsg->addr) {
cmd.type = MSP_TWI_CMD_WRITE_READ;
cmd.write_len = msg->len;
cmd.write_data = msg->buf;
cmd.read_len = nextmsg->len;
cmd.read_data = nextmsg->buf;
} else {
dev_dbg(&adap->dev,
"Non write-read dual messages unsupported\n");
return -EINVAL;
}
} else if (msg->flags & I2C_M_RD) {
cmd.type = MSP_TWI_CMD_READ;
cmd.read_len = msg->len;
cmd.read_data = msg->buf;
cmd.write_len = 0;
cmd.write_data = NULL;
} else {
cmd.type = MSP_TWI_CMD_WRITE;
cmd.read_len = 0;
cmd.read_data = NULL;
cmd.write_len = msg->len;
cmd.write_data = msg->buf;
}
if (msg->len == 0) {
dev_err(&adap->dev, "Zero-byte messages unsupported\n");
return -EINVAL;
}
cmd.addr = msg->addr;
if (msg->flags & I2C_M_TEN) {
pmcmsptwi_get_twi_config(&newcfg, data);
memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
/* Set the special 10-bit address flag */
newcfg.add10 = 1;
pmcmsptwi_set_twi_config(&newcfg, data);
}
/* Execute the command */
ret = pmcmsptwi_xfer_cmd(&cmd, data);
if (msg->flags & I2C_M_TEN)
pmcmsptwi_set_twi_config(&oldcfg, data);
dev_dbg(&adap->dev, "I2C %s of %d bytes ",
(msg->flags & I2C_M_RD) ? "read" : "write", msg->len);
if (ret != MSP_TWI_XFER_OK) {
/*
* TODO: We could potentially loop and retry in the case
* of MSP_TWI_XFER_TIMEOUT.
*/
dev_dbg(&adap->dev, "failed\n");
return -1;
}
dev_dbg(&adap->dev, "succeeded\n");
return 0;
}
static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
/* -- Initialization -- */
static struct i2c_algorithm pmcmsptwi_algo = {
.master_xfer = pmcmsptwi_master_xfer,
.functionality = pmcmsptwi_i2c_func,
};
static struct i2c_adapter pmcmsptwi_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo = &pmcmsptwi_algo,
.name = DRV_NAME,
};
static struct platform_driver pmcmsptwi_driver = {
.probe = pmcmsptwi_probe,
.remove = __devexit_p(pmcmsptwi_remove),
.driver {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init pmcmsptwi_init(void)
{
return platform_driver_register(&pmcmsptwi_driver);
}
static void __exit pmcmsptwi_exit(void)
{
platform_driver_unregister(&pmcmsptwi_driver);
}
MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
MODULE_LICENSE("GPL");
module_init(pmcmsptwi_init);
module_exit(pmcmsptwi_exit);

Просмотреть файл

@ -121,8 +121,7 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
if (rc) if (rc)
goto bail; goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 1, command, rc = pmac_i2c_xfer(bus, addrdir, 1, command,
read ? data->block : &data->block[1], &data->block[1], data->block[0]);
data->block[0]);
break; break;
default: default:

Просмотреть файл

@ -921,7 +921,14 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.class = plat->class; i2c->adap.class = plat->class;
} }
ret = i2c_add_adapter(&i2c->adap); /*
* If "dev->id" is negative we consider it as zero.
* The reason to do so is to avoid sysfs names that only make
* sense when there are multiple adapters.
*/
i2c->adap.nr = dev->id >= 0 ? dev->id : 0;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) { if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n"); printk(KERN_INFO "I2C: Failed to add bus\n");
goto eadapt; goto eadapt;

Просмотреть файл

@ -1,101 +0,0 @@
/*
* Embedded Planet RPX Lite MPC8xx CPM I2C interface.
* Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
*
* moved into proper i2c interface;
* Brad Parker (brad@heeltoe.com)
*
* RPX lite specific parts of the i2c interface
* Update: There actually isn't anything RPXLite-specific about this module.
* This should work for most any 8xx board. The console messages have been
* changed to eliminate RPXLite references.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/stddef.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-8xx.h>
#include <asm/mpc8xx.h>
#include <asm/commproc.h>
static void
rpx_iic_init(struct i2c_algo_8xx_data *data)
{
volatile cpm8xx_t *cp;
volatile immap_t *immap;
cp = cpmp; /* Get pointer to Communication Processor */
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
/* Check for and use a microcode relocation patch.
*/
if ((data->reloc = data->iip->iic_rpbase))
data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
data->i2c = (i2c8xx_t *)&(immap->im_i2c);
data->cp = cp;
/* Initialize Port B IIC pins.
*/
cp->cp_pbpar |= 0x00000030;
cp->cp_pbdir |= 0x00000030;
cp->cp_pbodr |= 0x00000030;
/* Allocate space for two transmit and two receive buffer
* descriptors in the DP ram.
*/
data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8);
/* ptr to i2c area */
data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
}
static int rpx_install_isr(int irq, void (*func)(void *), void *data)
{
/* install interrupt handler */
cpm_install_handler(irq, func, data);
return 0;
}
static struct i2c_algo_8xx_data rpx_data = {
.setisr = rpx_install_isr
};
static struct i2c_adapter rpx_ops = {
.owner = THIS_MODULE,
.name = "m8xx",
.id = I2C_HW_MPC8XX_EPON,
.algo_data = &rpx_data,
};
int __init i2c_rpx_init(void)
{
printk(KERN_INFO "i2c-rpx: i2c MPC8xx driver\n");
/* reset hardware to sane state */
rpx_iic_init(&rpx_data);
if (i2c_8xx_add_bus(&rpx_ops) < 0) {
printk(KERN_ERR "i2c-rpx: Unable to register with I2C\n");
return -ENODEV;
}
return 0;
}
void __exit i2c_rpx_exit(void)
{
i2c_8xx_del_bus(&rpx_ops);
}
MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
module_init(i2c_rpx_init);
module_exit(i2c_rpx_exit);

Просмотреть файл

@ -25,8 +25,6 @@
/* This interfaces to the I2C bus of the Savage4 to gain access to /* 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 the BT869 and possibly other I2C devices. The DDC bus is not
yet supported because its register is not memory-mapped. yet supported because its register is not memory-mapped.
However we leave the DDC code here, commented out, to make
it easier to add later.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
@ -37,36 +35,19 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <asm/io.h> #include <asm/io.h>
/* 3DFX defines */ /* device IDs */
#define PCI_CHIP_SAVAGE3D 0x8A20
#define PCI_CHIP_SAVAGE3D_MV 0x8A21
#define PCI_CHIP_SAVAGE4 0x8A22 #define PCI_CHIP_SAVAGE4 0x8A22
#define PCI_CHIP_SAVAGE2000 0x9102 #define PCI_CHIP_SAVAGE2000 0x9102
#define PCI_CHIP_PROSAVAGE_PM 0x8A25
#define PCI_CHIP_PROSAVAGE_KM 0x8A26
#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
#define PCI_CHIP_SAVAGE_MX 0x8c11
#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
#define PCI_CHIP_SAVAGE_IX 0x8c13
#define REG 0xff20 /* Serial Port 1 Register */ #define REG 0xff20 /* Serial Port 1 Register */
/* bit locations in the register */ /* bit locations in the register */
#define DDC_ENAB 0x00040000
#define DDC_SCL_OUT 0x00080000
#define DDC_SDA_OUT 0x00100000
#define DDC_SCL_IN 0x00200000
#define DDC_SDA_IN 0x00400000
#define I2C_ENAB 0x00000020 #define I2C_ENAB 0x00000020
#define I2C_SCL_OUT 0x00000001 #define I2C_SCL_OUT 0x00000001
#define I2C_SDA_OUT 0x00000002 #define I2C_SDA_OUT 0x00000002
#define I2C_SCL_IN 0x00000008 #define I2C_SCL_IN 0x00000008
#define I2C_SDA_IN 0x00000010 #define I2C_SDA_IN 0x00000010
/* initialization states */
#define INIT2 0x20
#define INIT3 0x04
/* delays */ /* delays */
#define CYCLE_DELAY 10 #define CYCLE_DELAY 10
#define TIMEOUT (HZ / 2) #define TIMEOUT (HZ / 2)

Просмотреть файл

@ -129,6 +129,7 @@ MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"
static struct pci_driver sis5595_driver; static struct pci_driver sis5595_driver;
static unsigned short sis5595_base; static unsigned short sis5595_base;
static struct pci_dev *sis5595_pdev;
static u8 sis5595_read(u8 reg) static u8 sis5595_read(u8 reg)
{ {
@ -379,6 +380,8 @@ MODULE_DEVICE_TABLE (pci, sis5595_ids);
static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id) static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
int err;
if (sis5595_setup(dev)) { if (sis5595_setup(dev)) {
dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n"); dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
return -ENODEV; return -ENODEV;
@ -389,20 +392,24 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_
sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x", sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x",
sis5595_base + SMB_INDEX); sis5595_base + SMB_INDEX);
return i2c_add_adapter(&sis5595_adapter); err = i2c_add_adapter(&sis5595_adapter);
} if (err) {
release_region(sis5595_base + SMB_INDEX, 2);
return err;
}
static void __devexit sis5595_remove(struct pci_dev *dev) /* Always return failure here. This is to allow other drivers to bind
{ * to this pci device. We don't really want to have control over the
i2c_del_adapter(&sis5595_adapter); * pci device, we only wanted to read as few register values from it.
release_region(sis5595_base + SMB_INDEX, 2); */
sis5595_pdev = pci_dev_get(dev);
return -ENODEV;
} }
static struct pci_driver sis5595_driver = { static struct pci_driver sis5595_driver = {
.name = "sis5595_smbus", .name = "sis5595_smbus",
.id_table = sis5595_ids, .id_table = sis5595_ids,
.probe = sis5595_probe, .probe = sis5595_probe,
.remove = __devexit_p(sis5595_remove),
}; };
static int __init i2c_sis5595_init(void) static int __init i2c_sis5595_init(void)
@ -413,6 +420,12 @@ static int __init i2c_sis5595_init(void)
static void __exit i2c_sis5595_exit(void) static void __exit i2c_sis5595_exit(void)
{ {
pci_unregister_driver(&sis5595_driver); pci_unregister_driver(&sis5595_driver);
if (sis5595_pdev) {
i2c_del_adapter(&sis5595_adapter);
release_region(sis5595_base + SMB_INDEX, 2);
pci_dev_put(sis5595_pdev);
sis5595_pdev = NULL;
}
} }
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");

Просмотреть файл

@ -0,0 +1,330 @@
/*
* Driver for the TAOS evaluation modules
* These devices include an I2C master which can be controlled over the
* serial port.
*
* Copyright (C) 2007 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; version 2 of the License.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/i2c.h>
#define TAOS_BUFFER_SIZE 63
#define TAOS_STATE_INIT 0
#define TAOS_STATE_IDLE 1
#define TAOS_STATE_SEND 2
#define TAOS_STATE_RECV 3
#define TAOS_CMD_RESET 0x12
static DECLARE_WAIT_QUEUE_HEAD(wq);
struct taos_data {
struct i2c_adapter adapter;
struct i2c_client *client;
int state;
u8 addr; /* last used address */
unsigned char buffer[TAOS_BUFFER_SIZE];
unsigned int pos; /* position inside the buffer */
};
/* TAOS TSL2550 EVM */
static struct i2c_board_info tsl2550_info = {
I2C_BOARD_INFO("tsl2550", 0x39),
.type = "tsl2550",
};
/* Instantiate i2c devices based on the adapter name */
static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
{
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
tsl2550_info.driver_name, tsl2550_info.addr);
return i2c_new_device(adapter, &tsl2550_info);
}
return NULL;
}
static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
struct serio *serio = adapter->algo_data;
struct taos_data *taos = serio_get_drvdata(serio);
char *p;
/* Encode our transaction. "@" is for the device address, "$" for the
SMBus command and "#" for the data. */
p = taos->buffer;
/* The device remembers the last used address, no need to send it
again if it's the same */
if (addr != taos->addr)
p += sprintf(p, "@%02X", addr);
switch (size) {
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE)
sprintf(p, "$#%02X", command);
else
sprintf(p, "$");
break;
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_WRITE)
sprintf(p, "$%02X#%02X", command, data->byte);
else
sprintf(p, "$%02X", command);
break;
default:
dev_dbg(&adapter->dev, "Unsupported transaction size %d\n",
size);
return -EINVAL;
}
/* Send the transaction to the TAOS EVM */
dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
taos->pos = 0;
taos->state = TAOS_STATE_SEND;
serio_write(serio, taos->buffer[0]);
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(250));
if (taos->state != TAOS_STATE_IDLE) {
dev_err(&adapter->dev, "Transaction failed "
"(state=%d, pos=%d)\n", taos->state, taos->pos);
taos->addr = 0;
return -EIO;
}
taos->addr = addr;
/* Start the transaction and read the answer */
taos->pos = 0;
taos->state = TAOS_STATE_RECV;
serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(150));
if (taos->state != TAOS_STATE_IDLE
|| taos->pos != 6) {
dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
taos->pos);
return -EIO;
}
dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
/* Interpret the returned string */
p = taos->buffer + 2;
p[3] = '\0';
if (!strcmp(p, "NAK"))
return -ENODEV;
if (read_write == I2C_SMBUS_WRITE) {
if (!strcmp(p, "ACK"))
return 0;
} else {
if (p[0] == 'x') {
data->byte = simple_strtol(p + 1, NULL, 16);
return 0;
}
}
return -EIO;
}
static u32 taos_smbus_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
}
static const struct i2c_algorithm taos_algorithm = {
.smbus_xfer = taos_smbus_xfer,
.functionality = taos_smbus_func,
};
static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
unsigned int flags)
{
struct taos_data *taos = serio_get_drvdata(serio);
switch (taos->state) {
case TAOS_STATE_INIT:
taos->buffer[taos->pos++] = data;
if (data == ':'
|| taos->pos == TAOS_BUFFER_SIZE - 1) {
taos->buffer[taos->pos] = '\0';
taos->state = TAOS_STATE_IDLE;
wake_up_interruptible(&wq);
}
break;
case TAOS_STATE_SEND:
if (taos->buffer[++taos->pos])
serio_write(serio, taos->buffer[taos->pos]);
else {
taos->state = TAOS_STATE_IDLE;
wake_up_interruptible(&wq);
}
break;
case TAOS_STATE_RECV:
taos->buffer[taos->pos++] = data;
if (data == ']') {
taos->buffer[taos->pos] = '\0';
taos->state = TAOS_STATE_IDLE;
wake_up_interruptible(&wq);
}
break;
}
return IRQ_HANDLED;
}
/* Extract the adapter name from the buffer received after reset.
The buffer is modified and a pointer inside the buffer is returned. */
static char *taos_adapter_name(char *buffer)
{
char *start, *end;
start = strstr(buffer, "TAOS ");
if (!start)
return NULL;
end = strchr(start, '\r');
if (!end)
return NULL;
*end = '\0';
return start;
}
static int taos_connect(struct serio *serio, struct serio_driver *drv)
{
struct taos_data *taos;
struct i2c_adapter *adapter;
char *name;
int err;
taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
if (!taos) {
err = -ENOMEM;
goto exit;
}
taos->state = TAOS_STATE_INIT;
serio_set_drvdata(serio, taos);
err = serio_open(serio, drv);
if (err)
goto exit_kfree;
adapter = &taos->adapter;
adapter->owner = THIS_MODULE;
adapter->algo = &taos_algorithm;
adapter->algo_data = serio;
adapter->dev.parent = &serio->dev;
/* Reset the TAOS evaluation module to identify it */
serio_write(serio, TAOS_CMD_RESET);
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(2000));
if (taos->state != TAOS_STATE_IDLE) {
err = -ENODEV;
dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, "
"pos=%d)\n", taos->state, taos->pos);
goto exit_close;
}
name = taos_adapter_name(taos->buffer);
if (!name) {
err = -ENODEV;
dev_err(&serio->dev, "TAOS EVM identification failed\n");
goto exit_close;
}
strlcpy(adapter->name, name, sizeof(adapter->name));
err = i2c_add_adapter(adapter);
if (err)
goto exit_close;
dev_dbg(&serio->dev, "Connected to TAOS EVM\n");
taos->client = taos_instantiate_device(adapter);
return 0;
exit_close:
serio_close(serio);
exit_kfree:
serio_set_drvdata(serio, NULL);
kfree(taos);
exit:
return err;
}
static void taos_disconnect(struct serio *serio)
{
struct taos_data *taos = serio_get_drvdata(serio);
if (taos->client)
i2c_unregister_device(taos->client);
i2c_del_adapter(&taos->adapter);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(taos);
dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n");
}
static struct serio_device_id taos_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_TAOSEVM,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, taos_serio_ids);
static struct serio_driver taos_drv = {
.driver = {
.name = "taos-evm",
},
.description = "TAOS evaluation module driver",
.id_table = taos_serio_ids,
.connect = taos_connect,
.disconnect = taos_disconnect,
.interrupt = taos_interrupt,
};
static int __init taos_init(void)
{
return serio_register_driver(&taos_drv);
}
static void __exit taos_exit(void)
{
serio_unregister_driver(&taos_drv);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("TAOS evaluation module driver");
MODULE_LICENSE("GPL");
module_init(taos_init);
module_exit(taos_exit);

Просмотреть файл

@ -235,7 +235,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
if (!(vt596_features & FEATURE_I2CBLOCK)) if (!(vt596_features & FEATURE_I2CBLOCK))
goto exit_unsupported; goto exit_unsupported;
if (read_write == I2C_SMBUS_READ) if (read_write == I2C_SMBUS_READ)
outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); outb_p(data->block[0], SMBHSTDAT0);
/* Fall through */ /* Fall through */
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:
outb_p(command, SMBHSTCMD); outb_p(command, SMBHSTCMD);

Просмотреть файл

@ -310,8 +310,6 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
if (rw == I2C_SMBUS_READ)
data->block[0] = I2C_SMBUS_BLOCK_MAX; /* For now */
len = data->block[0]; len = data->block[0];
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL; return -EINVAL;
@ -388,7 +386,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
}; };
static struct scx200_acb_iface *scx200_acb_list; static struct scx200_acb_iface *scx200_acb_list;
static DECLARE_MUTEX(scx200_acb_list_mutex); static DEFINE_MUTEX(scx200_acb_list_mutex);
static __init int scx200_acb_probe(struct scx200_acb_iface *iface) static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
{ {
@ -472,10 +470,10 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
return -ENODEV; return -ENODEV;
} }
down(&scx200_acb_list_mutex); mutex_lock(&scx200_acb_list_mutex);
iface->next = scx200_acb_list; iface->next = scx200_acb_list;
scx200_acb_list = iface; scx200_acb_list = iface;
up(&scx200_acb_list_mutex); mutex_unlock(&scx200_acb_list_mutex);
return 0; return 0;
} }
@ -633,10 +631,10 @@ static void __exit scx200_acb_cleanup(void)
{ {
struct scx200_acb_iface *iface; struct scx200_acb_iface *iface;
down(&scx200_acb_list_mutex); mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) { while ((iface = scx200_acb_list) != NULL) {
scx200_acb_list = iface->next; scx200_acb_list = iface->next;
up(&scx200_acb_list_mutex); mutex_unlock(&scx200_acb_list_mutex);
i2c_del_adapter(&iface->adapter); i2c_del_adapter(&iface->adapter);
@ -648,9 +646,9 @@ static void __exit scx200_acb_cleanup(void)
release_region(iface->base, 8); release_region(iface->base, 8);
kfree(iface); kfree(iface);
down(&scx200_acb_list_mutex); mutex_lock(&scx200_acb_list_mutex);
} }
up(&scx200_acb_list_mutex); mutex_unlock(&scx200_acb_list_mutex);
} }
module_init(scx200_acb_init); module_init(scx200_acb_init);

Просмотреть файл

@ -5,7 +5,7 @@
menu "Miscellaneous I2C Chip support" menu "Miscellaneous I2C Chip support"
config SENSORS_DS1337 config SENSORS_DS1337
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
depends on EXPERIMENTAL depends on EXPERIMENTAL
help help
If you say yes here you get support for Dallas Semiconductor If you say yes here you get support for Dallas Semiconductor
@ -14,8 +14,11 @@ config SENSORS_DS1337
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called ds1337. will be called ds1337.
This driver is deprecated and will be dropped soon. Use
rtc-ds1307 instead.
config SENSORS_DS1374 config SENSORS_DS1374
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
depends on EXPERIMENTAL depends on EXPERIMENTAL
help help
If you say yes here you get support for Dallas Semiconductor If you say yes here you get support for Dallas Semiconductor
@ -24,6 +27,19 @@ config SENSORS_DS1374
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called ds1374. will be called ds1374.
This driver is deprecated and will be dropped soon. Use
rtc-ds1374 instead.
config DS1682
tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
depends on EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
DS1682 Total Elapsed Time Recorder.
This driver can also be built as a module. If so, the module
will be called ds1682.
config SENSORS_EEPROM config SENSORS_EEPROM
tristate "EEPROM reader" tristate "EEPROM reader"
depends on EXPERIMENTAL depends on EXPERIMENTAL
@ -101,7 +117,7 @@ config TPS65010
will be called tps65010. will be called tps65010.
config SENSORS_M41T00 config SENSORS_M41T00
tristate "ST M41T00 RTC chip" tristate "ST M41T00 RTC chip (DEPRECATED)"
depends on PPC32 depends on PPC32
help help
If you say yes here you get support for the ST M41T00 RTC chip. If you say yes here you get support for the ST M41T00 RTC chip.
@ -109,6 +125,9 @@ config SENSORS_M41T00
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called m41t00. will be called m41t00.
This driver is deprecated and will be dropped soon. Use
rtc-ds1307 or rtc-m41t80 instead.
config SENSORS_MAX6875 config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor" tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL depends on EXPERIMENTAL
@ -124,4 +143,14 @@ config SENSORS_MAX6875
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called max6875. will be called max6875.
config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor"
depends on EXPERIMENTAL
help
If you say yes here you get support for the Taos TSL2550
ambient light sensor.
This driver can also be built as a module. If so, the module
will be called tsl2550.
endmenu endmenu

Просмотреть файл

@ -4,6 +4,7 @@
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
@ -12,6 +13,7 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG

259
drivers/i2c/chips/ds1682.c Normal file
Просмотреть файл

@ -0,0 +1,259 @@
/*
* Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
*
* Written by: Grant Likely <grant.likely@secretlab.ca>
*
* Copyright (C) 2007 Secret Lab Technologies Ltd.
*
* 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.
*/
/*
* The DS1682 elapsed timer recorder is a simple device that implements
* one elapsed time counter, one event counter, an alarm signal and 10
* bytes of general purpose EEPROM.
*
* This driver provides access to the DS1682 counters and user data via
* the sysfs. The following attributes are added to the device node:
* elapsed_time (u32): Total elapsed event time in ms resolution
* alarm_time (u32): When elapsed time exceeds the value in alarm_time,
* then the alarm pin is asserted.
* event_count (u16): number of times the event pin has gone low.
* eeprom (u8[10]): general purpose EEPROM
*
* Counter registers and user data are both read/write unless the device
* has been write protected. This driver does not support turning off write
* protection. Once write protection is turned on, it is impossible to
* turn it off again, so I have left the feature out of this driver to avoid
* accidental enabling, but it is trivial to add write protect support.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include <linux/hwmon-sysfs.h>
/* Device registers */
#define DS1682_REG_CONFIG 0x00
#define DS1682_REG_ALARM 0x01
#define DS1682_REG_ELAPSED 0x05
#define DS1682_REG_EVT_CNTR 0x09
#define DS1682_REG_EEPROM 0x0b
#define DS1682_REG_RESET 0x1d
#define DS1682_REG_WRITE_DISABLE 0x1e
#define DS1682_REG_WRITE_MEM_DISABLE 0x1f
#define DS1682_EEPROM_SIZE 10
/*
* Generic counter attributes
*/
static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
__le32 val = 0;
int rc;
dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
/* Read the register */
rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
(u8 *) & val);
if (rc < 0)
return -EIO;
/* Special case: the 32 bit regs are time values with 1/4s
* resolution, scale them up to milliseconds */
if (sattr->nr == 4)
return sprintf(buf, "%llu\n", ((u64) le32_to_cpu(val)) * 250);
/* Format the output string and return # of bytes */
return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
}
static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
char *endp;
u64 val;
__le32 val_le;
int rc;
dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
/* Decode input */
val = simple_strtoull(buf, &endp, 0);
if (buf == endp) {
dev_dbg(dev, "input string not a number\n");
return -EINVAL;
}
/* Special case: the 32 bit regs are time values with 1/4s
* resolution, scale input down to quarter-seconds */
if (sattr->nr == 4)
do_div(val, 250);
/* write out the value */
val_le = cpu_to_le32(val);
rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
(u8 *) & val_le);
if (rc < 0) {
dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
sattr->index, sattr->nr);
return -EIO;
}
return count;
}
/*
* Simple register attributes
*/
static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
ds1682_store, 4, DS1682_REG_ELAPSED);
static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
ds1682_store, 4, DS1682_REG_ALARM);
static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
ds1682_store, 2, DS1682_REG_EVT_CNTR);
static const struct attribute_group ds1682_group = {
.attrs = (struct attribute *[]) {
&sensor_dev_attr_elapsed_time.dev_attr.attr,
&sensor_dev_attr_alarm_time.dev_attr.attr,
&sensor_dev_attr_event_count.dev_attr.attr,
NULL,
},
};
/*
* User data attribute
*/
static ssize_t ds1682_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
int rc;
dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
buf, off, count);
if (off >= DS1682_EEPROM_SIZE)
return 0;
if (off + count > DS1682_EEPROM_SIZE)
count = DS1682_EEPROM_SIZE - off;
rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
count, buf);
if (rc < 0)
return -EIO;
return count;
}
static ssize_t ds1682_eeprom_write(struct kobject *kobj, char *buf, loff_t off,
size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
buf, off, count);
if (off >= DS1682_EEPROM_SIZE)
return -ENOSPC;
if (off + count > DS1682_EEPROM_SIZE)
count = DS1682_EEPROM_SIZE - off;
/* Write out to the device */
if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
count, buf) < 0)
return -EIO;
return count;
}
static struct bin_attribute ds1682_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO | S_IWUSR,
.owner = THIS_MODULE,
},
.size = DS1682_EEPROM_SIZE,
.read = ds1682_eeprom_read,
.write = ds1682_eeprom_write,
};
/*
* Called when a ds1682 device is matched with this driver
*/
static int ds1682_probe(struct i2c_client *client)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(&client->dev, "i2c bus does not support the ds1682\n");
rc = -ENODEV;
goto exit;
}
rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
if (rc)
goto exit;
rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
if (rc)
goto exit_bin_attr;
return 0;
exit_bin_attr:
sysfs_remove_group(&client->dev.kobj, &ds1682_group);
exit:
return rc;
}
static int ds1682_remove(struct i2c_client *client)
{
sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
sysfs_remove_group(&client->dev.kobj, &ds1682_group);
return 0;
}
static struct i2c_driver ds1682_driver = {
.driver = {
.name = "ds1682",
},
.probe = ds1682_probe,
.remove = ds1682_remove,
};
static int __init ds1682_init(void)
{
return i2c_add_driver(&ds1682_driver);
}
static void __exit ds1682_exit(void)
{
i2c_del_driver(&ds1682_driver);
}
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
MODULE_LICENSE("GPL");
module_init(ds1682_init);
module_exit(ds1682_exit);

Просмотреть файл

@ -88,8 +88,10 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice)
dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX) for (i = slice << 5; i < (slice + 1) << 5; i += 32)
if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX) if (i2c_smbus_read_i2c_block_data(client, i,
32, data->data + i)
!= 32)
goto exit; goto exit;
} else { } else {
if (i2c_smbus_write_byte(client, slice << 5)) { if (i2c_smbus_write_byte(client, slice << 5)) {

Просмотреть файл

@ -106,6 +106,7 @@ static void max6875_update_slice(struct i2c_client *client, int slice)
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
if (i2c_smbus_read_i2c_block_data(client, if (i2c_smbus_read_i2c_block_data(client,
MAX6875_CMD_BLK_READ, MAX6875_CMD_BLK_READ,
SLICE_SIZE,
buf) != SLICE_SIZE) { buf) != SLICE_SIZE) {
goto exit_up; goto exit_up;
} }

460
drivers/i2c/chips/tsl2550.c Normal file
Просмотреть файл

@ -0,0 +1,460 @@
/*
* tsl2550.c - Linux kernel modules for ambient light sensor
*
* Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
* Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
*
* 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/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#define TSL2550_DRV_NAME "tsl2550"
#define DRIVER_VERSION "1.1.1"
/*
* Defines
*/
#define TSL2550_POWER_DOWN 0x00
#define TSL2550_POWER_UP 0x03
#define TSL2550_STANDARD_RANGE 0x18
#define TSL2550_EXTENDED_RANGE 0x1d
#define TSL2550_READ_ADC0 0x43
#define TSL2550_READ_ADC1 0x83
/*
* Structs
*/
struct tsl2550_data {
struct i2c_client *client;
struct mutex update_lock;
unsigned int power_state : 1;
unsigned int operating_mode : 1;
};
/*
* Global data
*/
static const u8 TSL2550_MODE_RANGE[2] = {
TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
};
/*
* Management functions
*/
static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
{
struct tsl2550_data *data = i2c_get_clientdata(client);
int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
data->operating_mode = mode;
return ret;
}
static int tsl2550_set_power_state(struct i2c_client *client, int state)
{
struct tsl2550_data *data = i2c_get_clientdata(client);
int ret;
if (state == 0)
ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
else {
ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
/* On power up we should reset operating mode also... */
tsl2550_set_operating_mode(client, data->operating_mode);
}
data->power_state = state;
return ret;
}
static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
{
unsigned long end;
int loop = 0, ret = 0;
/*
* Read ADC channel waiting at most 400ms (see data sheet for further
* info).
* To avoid long busy wait we spin for few milliseconds then
* start sleeping.
*/
end = jiffies + msecs_to_jiffies(400);
while (time_before(jiffies, end)) {
i2c_smbus_write_byte(client, cmd);
if (loop++ < 5)
mdelay(1);
else
msleep(1);
ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
else if (ret & 0x0080)
break;
}
if (!(ret & 0x80))
return -EIO;
return ret & 0x7f; /* remove the "valid" bit */
}
/*
* LUX calculation
*/
#define TSL2550_MAX_LUX 1846
static const u8 ratio_lut[] = {
100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 98, 98, 98, 98, 98,
98, 98, 97, 97, 97, 97, 97, 96,
96, 96, 96, 95, 95, 95, 94, 94,
93, 93, 93, 92, 92, 91, 91, 90,
89, 89, 88, 87, 87, 86, 85, 84,
83, 82, 81, 80, 79, 78, 77, 75,
74, 73, 71, 69, 68, 66, 64, 62,
60, 58, 56, 54, 52, 49, 47, 44,
42, 41, 40, 40, 39, 39, 38, 38,
37, 37, 37, 36, 36, 36, 35, 35,
35, 35, 34, 34, 34, 34, 33, 33,
33, 33, 32, 32, 32, 32, 32, 31,
31, 31, 31, 31, 30, 30, 30, 30,
30,
};
static const u16 count_lut[] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46,
49, 53, 57, 61, 65, 69, 73, 77,
81, 85, 89, 93, 97, 101, 105, 109,
115, 123, 131, 139, 147, 155, 163, 171,
179, 187, 195, 203, 211, 219, 227, 235,
247, 263, 279, 295, 311, 327, 343, 359,
375, 391, 407, 423, 439, 455, 471, 487,
511, 543, 575, 607, 639, 671, 703, 735,
767, 799, 831, 863, 895, 927, 959, 991,
1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
};
/*
* This function is described into Taos TSL2550 Designer's Notebook
* pages 2, 3.
*/
static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
{
unsigned int lux;
/* Look up count from channel values */
u16 c0 = count_lut[ch0];
u16 c1 = count_lut[ch1];
/*
* Calculate ratio.
* Note: the "128" is a scaling factor
*/
u8 r = 128;
/* Avoid division by 0 and count 1 cannot be greater than count 0 */
if (c0 && (c1 <= c0))
r = c1 * 128 / c0;
else
return -1;
/* Calculate LUX */
lux = ((c0 - c1) * ratio_lut[r]) / 256;
/* LUX range check */
return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
}
/*
* SysFS support
*/
static ssize_t tsl2550_show_power_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%u\n", data->power_state);
}
static ssize_t tsl2550_store_power_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct tsl2550_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
int ret;
if (val < 0 || val > 1)
return -EINVAL;
mutex_lock(&data->update_lock);
ret = tsl2550_set_power_state(client, val);
mutex_unlock(&data->update_lock);
if (ret < 0)
return ret;
return count;
}
static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
tsl2550_show_power_state, tsl2550_store_power_state);
static ssize_t tsl2550_show_operating_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
return sprintf(buf, "%u\n", data->operating_mode);
}
static ssize_t tsl2550_store_operating_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct tsl2550_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
int ret;
if (val < 0 || val > 1)
return -EINVAL;
if (data->power_state == 0)
return -EBUSY;
mutex_lock(&data->update_lock);
ret = tsl2550_set_operating_mode(client, val);
mutex_unlock(&data->update_lock);
if (ret < 0)
return ret;
return count;
}
static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
tsl2550_show_operating_mode, tsl2550_store_operating_mode);
static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
{
u8 ch0, ch1;
int ret;
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
if (ret < 0)
return ret;
ch0 = ret;
mdelay(1);
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
if (ret < 0)
return ret;
ch1 = ret;
/* Do the job */
ret = tsl2550_calculate_lux(ch0, ch1);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", ret);
}
static ssize_t tsl2550_show_lux1_input(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct tsl2550_data *data = i2c_get_clientdata(client);
int ret;
/* No LUX data if not operational */
if (!data->power_state)
return -EBUSY;
mutex_lock(&data->update_lock);
ret = __tsl2550_show_lux(client, buf);
mutex_unlock(&data->update_lock);
return ret;
}
static DEVICE_ATTR(lux1_input, S_IRUGO,
tsl2550_show_lux1_input, NULL);
static struct attribute *tsl2550_attributes[] = {
&dev_attr_power_state.attr,
&dev_attr_operating_mode.attr,
&dev_attr_lux1_input.attr,
NULL
};
static const struct attribute_group tsl2550_attr_group = {
.attrs = tsl2550_attributes,
};
/*
* Initialization function
*/
static int tsl2550_init_client(struct i2c_client *client)
{
struct tsl2550_data *data = i2c_get_clientdata(client);
int err;
/*
* Probe the chip. To do so we try to power up the device and then to
* read back the 0x03 code
*/
err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
if (err < 0)
return err;
mdelay(1);
if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
return -ENODEV;
data->power_state = 1;
/* Set the default operating mode */
err = i2c_smbus_write_byte(client,
TSL2550_MODE_RANGE[data->operating_mode]);
if (err < 0)
return err;
return 0;
}
/*
* I2C init/probing/exit functions
*/
static struct i2c_driver tsl2550_driver;
static int __devinit tsl2550_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct tsl2550_data *data;
int *opmode, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
err = -EIO;
goto exit;
}
data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
data->client = client;
i2c_set_clientdata(client, data);
/* Check platform data */
opmode = client->dev.platform_data;
if (opmode) {
if (*opmode < 0 || *opmode > 1) {
dev_err(&client->dev, "invalid operating_mode (%d)\n",
*opmode);
err = -EINVAL;
goto exit_kfree;
}
data->operating_mode = *opmode;
} else
data->operating_mode = 0; /* default mode is standard */
dev_info(&client->dev, "%s operating mode\n",
data->operating_mode ? "extended" : "standard");
mutex_init(&data->update_lock);
/* Initialize the TSL2550 chip */
err = tsl2550_init_client(client);
if (err)
goto exit_kfree;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
if (err)
goto exit_kfree;
dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
return 0;
exit_kfree:
kfree(data);
exit:
return err;
}
static int __devexit tsl2550_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
/* Power down the device */
tsl2550_set_power_state(client, 0);
kfree(i2c_get_clientdata(client));
return 0;
}
static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
.owner = THIS_MODULE,
},
.probe = tsl2550_probe,
.remove = __devexit_p(tsl2550_remove),
};
static int __init tsl2550_init(void)
{
return i2c_add_driver(&tsl2550_driver);
}
static void __exit tsl2550_exit(void)
{
i2c_del_driver(&tsl2550_driver);
}
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
module_init(tsl2550_init);
module_exit(tsl2550_exit);

Просмотреть файл

@ -207,6 +207,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type);
* i2c_new_device - instantiate an i2c device for use with a new style driver * i2c_new_device - instantiate an i2c device for use with a new style driver
* @adap: the adapter managing the device * @adap: the adapter managing the device
* @info: describes one I2C device; bus_num is ignored * @info: describes one I2C device; bus_num is ignored
* Context: can sleep
* *
* Create a device to work with a new style i2c driver, where binding is * Create a device to work with a new style i2c driver, where binding is
* handled through driver model probe()/remove() methods. This call is not * handled through driver model probe()/remove() methods. This call is not
@ -255,6 +256,7 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
/** /**
* i2c_unregister_device - reverse effect of i2c_new_device() * i2c_unregister_device - reverse effect of i2c_new_device()
* @client: value returned from i2c_new_device() * @client: value returned from i2c_new_device()
* Context: can sleep
*/ */
void i2c_unregister_device(struct i2c_client *client) void i2c_unregister_device(struct i2c_client *client)
{ {
@ -379,6 +381,7 @@ out_list:
/** /**
* i2c_add_adapter - declare i2c adapter, use dynamic bus number * i2c_add_adapter - declare i2c adapter, use dynamic bus number
* @adapter: the adapter to add * @adapter: the adapter to add
* Context: can sleep
* *
* This routine is used to declare an I2C adapter when its bus number * This routine is used to declare an I2C adapter when its bus number
* doesn't matter. Examples: for I2C adapters dynamically added by * doesn't matter. Examples: for I2C adapters dynamically added by
@ -416,6 +419,7 @@ EXPORT_SYMBOL(i2c_add_adapter);
/** /**
* i2c_add_numbered_adapter - declare i2c adapter, use static bus number * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
* @adap: the adapter to register (with adap->nr initialized) * @adap: the adapter to register (with adap->nr initialized)
* Context: can sleep
* *
* This routine is used to declare an I2C adapter when its bus number * This routine is used to declare an I2C adapter when its bus number
* matters. Example: for I2C adapters from system-on-chip CPUs, or * matters. Example: for I2C adapters from system-on-chip CPUs, or
@ -463,6 +467,14 @@ retry:
} }
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
/**
* i2c_del_adapter - unregister I2C adapter
* @adap: the adapter being unregistered
* Context: can sleep
*
* This unregisters an I2C adapter which was previously registered
* by @i2c_add_adapter or @i2c_add_numbered_adapter.
*/
int i2c_del_adapter(struct i2c_adapter *adap) int i2c_del_adapter(struct i2c_adapter *adap)
{ {
struct list_head *item, *_n; struct list_head *item, *_n;
@ -598,6 +610,7 @@ EXPORT_SYMBOL(i2c_register_driver);
/** /**
* i2c_del_driver - unregister I2C driver * i2c_del_driver - unregister I2C driver
* @driver: the driver being unregistered * @driver: the driver being unregistered
* Context: can sleep
*/ */
void i2c_del_driver(struct i2c_driver *driver) void i2c_del_driver(struct i2c_driver *driver)
{ {
@ -1331,10 +1344,14 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
EXPORT_SYMBOL(i2c_smbus_write_block_data); EXPORT_SYMBOL(i2c_smbus_write_block_data);
/* Returns the number of read bytes */ /* Returns the number of read bytes */
s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
u8 length, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
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, if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
I2C_SMBUS_READ,command, I2C_SMBUS_READ,command,
I2C_SMBUS_I2C_BLOCK_DATA,&data)) I2C_SMBUS_I2C_BLOCK_DATA,&data))
@ -1455,7 +1472,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) { if (read_write == I2C_SMBUS_READ) {
msg[1].len = I2C_SMBUS_BLOCK_MAX; msg[1].len = data->block[0];
} else { } else {
msg[0].len = data->block[0] + 1; msg[0].len = data->block[0] + 1;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
@ -1511,9 +1528,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
data->word = msgbuf1[0] | (msgbuf1[1] << 8); data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
/* fixed at 32 for now */ for (i = 0; i < data->block[0]; i++)
data->block[0] = I2C_SMBUS_BLOCK_MAX;
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
data->block[i+1] = msgbuf1[i]; data->block[i+1] = msgbuf1[i];
break; break;
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:

Просмотреть файл

@ -283,6 +283,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
(data_arg.size != I2C_SMBUS_WORD_DATA) && (data_arg.size != I2C_SMBUS_WORD_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) && (data_arg.size != I2C_SMBUS_PROC_CALL) &&
(data_arg.size != I2C_SMBUS_BLOCK_DATA) && (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
(data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
dev_dbg(&client->adapter->dev, dev_dbg(&client->adapter->dev,
@ -329,10 +330,18 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
if ((data_arg.size == I2C_SMBUS_PROC_CALL) || if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
(data_arg.read_write == I2C_SMBUS_WRITE)) { (data_arg.read_write == I2C_SMBUS_WRITE)) {
if (copy_from_user(&temp, data_arg.data, datasize)) if (copy_from_user(&temp, data_arg.data, datasize))
return -EFAULT; return -EFAULT;
} }
if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
/* Convert old I2C block commands to the new
convention. This preserves binary compatibility. */
data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
if (data_arg.read_write == I2C_SMBUS_READ)
temp.block[0] = I2C_SMBUS_BLOCK_MAX;
}
res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
data_arg.read_write, data_arg.read_write,
data_arg.command,data_arg.size,&temp); data_arg.command,data_arg.size,&temp);

Просмотреть файл

@ -67,26 +67,6 @@ static struct i2c_driver wf_sat_driver = {
.detach_client = wf_sat_detach, .detach_client = wf_sat_detach,
}; };
/*
* XXX i2c_smbus_read_i2c_block_data doesn't pass the requested
* length down to the low-level driver, so we use this, which
* works well enough with the SMU i2c driver code...
*/
static int sat_read_block(struct i2c_client *client, u8 command,
u8 *values, int len)
{
union i2c_smbus_data data;
int err;
data.block[0] = len;
err = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA,
&data);
if (!err)
memcpy(values, data.block, len);
return err;
}
struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
unsigned int *size) unsigned int *size)
{ {
@ -124,8 +104,8 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
return NULL; return NULL;
for (i = 0; i < len; i += 4) { for (i = 0; i < len; i += 4) {
err = sat_read_block(&sat->i2c, 0xa, data, 4); err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data);
if (err) { if (err < 0) {
printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
err); err);
goto fail; goto fail;
@ -157,8 +137,8 @@ static int wf_sat_read_cache(struct wf_sat *sat)
{ {
int err; int err;
err = sat_read_block(&sat->i2c, 0x3f, sat->cache, 16); err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache);
if (err) if (err < 0)
return err; return err;
sat->last_read = jiffies; sat->last_read = jiffies;
#ifdef LOTSA_DEBUG #ifdef LOTSA_DEBUG

Просмотреть файл

@ -9,6 +9,9 @@
* *
* based on a lot of other RTC drivers. * based on a lot of other RTC drivers.
* *
* Information and datasheet:
* http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
@ -26,7 +29,7 @@
* Two bytes need to be written to read a single register, * Two bytes need to be written to read a single register,
* while most other chips just require one and take the second * while most other chips just require one and take the second
* one as the data to be written. To prevent corrupting * one as the data to be written. To prevent corrupting
* unknown chips, the user must explicitely set the probe parameter. * unknown chips, the user must explicitly set the probe parameter.
*/ */
static unsigned short normal_i2c[] = { I2C_CLIENT_END }; static unsigned short normal_i2c[] = { I2C_CLIENT_END };

Просмотреть файл

@ -2,8 +2,6 @@
#define __MATROXFB_CRTC2_H__ #define __MATROXFB_CRTC2_H__
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include "matroxfb_base.h" #include "matroxfb_base.h"
struct matroxfb_dh_fb_info { struct matroxfb_dh_fb_info {

Просмотреть файл

@ -90,7 +90,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
const u8 *values); const u8 *values);
/* Returns the number of read bytes */ /* Returns the number of read bytes */
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
u8 command, u8 *values); u8 command, u8 length, u8 *values);
extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
u8 command, u8 length, u8 command, u8 length,
const u8 *values); const u8 *values);
@ -150,15 +150,20 @@ struct i2c_driver {
/** /**
* struct i2c_client - represent an I2C slave device * struct i2c_client - represent an I2C slave device
* @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
* I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
* @addr: Address used on the I2C bus connected to the parent adapter. * @addr: Address used on the I2C bus connected to the parent adapter.
* @name: Indicates the type of the device, usually a chip name that's * @name: Indicates the type of the device, usually a chip name that's
* generic enough to hide second-sourcing and compatible revisions. * generic enough to hide second-sourcing and compatible revisions.
* @adapter: manages the bus segment hosting this I2C device
* @dev: Driver model device node for the slave. * @dev: Driver model device node for the slave.
* @irq: indicates the IRQ generated by this device (if any)
* @driver_name: Identifies new-style driver used with this device; also * @driver_name: Identifies new-style driver used with this device; also
* used as the module name for hotplug/coldplug modprobe support. * used as the module name for hotplug/coldplug modprobe support.
* *
* An i2c_client identifies a single device (i.e. chip) connected to an * An i2c_client identifies a single device (i.e. chip) connected to an
* i2c bus. The behaviour is defined by the routines of the driver. * i2c bus. The behaviour exposed to Linux is defined by the driver
* managing the device.
*/ */
struct i2c_client { struct i2c_client {
unsigned short flags; /* div., see below */ unsigned short flags; /* div., see below */
@ -180,7 +185,8 @@ struct i2c_client {
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
{ {
return to_i2c_client(container_of(kobj, struct device, kobj)); struct device * const dev = container_of(kobj, struct device, kobj);
return to_i2c_client(dev);
} }
static inline void *i2c_get_clientdata (struct i2c_client *dev) static inline void *i2c_get_clientdata (struct i2c_client *dev)
@ -201,7 +207,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
* @addr: stored in i2c_client.addr * @addr: stored in i2c_client.addr
* @platform_data: stored in i2c_client.dev.platform_data * @platform_data: stored in i2c_client.dev.platform_data
* @irq: stored in i2c_client.irq * @irq: stored in i2c_client.irq
*
* I2C doesn't actually support hardware probing, although controllers and * I2C doesn't actually support hardware probing, although controllers and
* devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
* a device at a given address. Drivers commonly need more information than * a device at a given address. Drivers commonly need more information than
@ -210,7 +216,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
* i2c_board_info is used to build tables of information listing I2C devices * i2c_board_info is used to build tables of information listing I2C devices
* that are present. This information is used to grow the driver model tree * that are present. This information is used to grow the driver model tree
* for "new style" I2C drivers. For mainboards this is done statically using * for "new style" I2C drivers. For mainboards this is done statically using
* i2c_register_board_info(), where @bus_num represents an adapter that isn't * i2c_register_board_info(); bus numbers identify adapters that aren't
* yet available. For add-on boards, i2c_new_device() does this dynamically * yet available. For add-on boards, i2c_new_device() does this dynamically
* with the adapter already known. * with the adapter already known.
*/ */
@ -518,8 +524,9 @@ union i2c_smbus_data {
#define I2C_SMBUS_WORD_DATA 3 #define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_DATA 6 #define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8
/* ----- commands for the ioctl like i2c_command call: /* ----- commands for the ioctl like i2c_command call:

Просмотреть файл

@ -371,6 +371,7 @@
#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385 #define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385
#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c #define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 #define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390
#define PCI_DEVICE_ID_ATI_IXP700_SMBUS 0x4395
#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c #define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c
#define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_VENDOR_ID_VLSI 0x1004

Просмотреть файл

@ -209,5 +209,6 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_PENMOUNT 0x31 #define SERIO_PENMOUNT 0x31
#define SERIO_TOUCHRIGHT 0x32 #define SERIO_TOUCHRIGHT 0x32
#define SERIO_TOUCHWIN 0x33 #define SERIO_TOUCHWIN 0x33
#define SERIO_TAOSEVM 0x34
#endif #endif