Commit 40aba218 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  i2c: Clearly mark ACPI drivers as such
  i2c: Add driver for SMBus Control Method Interface
  i2c-pnx: Correct use of request_region/request_mem_region
  MAINTAINERS: Add maintainer for AT24 and PCA9564/PCA9665
  i2c-piix4: Add AMD SB900 SMBus device ID
  i2c/chips: Remove deprecated pcf8574 driver
  i2c/chips: Remove deprecated pca9539 driver
  i2c/chips: Remove deprecated pcf8575 driver
  gpio/pcf857x: Copy i2c_device_id from old pcf8574 driver
  i2c/scx200_acb: Provide more information on bus errors
  i2c: Provide compatibility links for i2c adapters
  i2c: Convert i2c adapters to bus devices
  i2c: Convert i2c clients to a device type
  i2c/tsl2550: Use combined SMBus transactions
  i2c-taos-evm: Switch echo off to improve performance
  i2c: Drop unused i2c_driver.id field
parents b64ada6b cfd550ed
...@@ -8,6 +8,8 @@ Supported adapters: ...@@ -8,6 +8,8 @@ Supported adapters:
Datasheet: Only available via NDA from ServerWorks Datasheet: Only available via NDA from ServerWorks
* ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges * ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
Datasheet: Not publicly available Datasheet: Not publicly available
* AMD SB900
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
......
Kernel driver pca9539
=====================
NOTE: this driver is deprecated and will be dropped soon, use
drivers/gpio/pca9539.c instead.
Supported chips:
* Philips PCA9539
Prefix: 'pca9539'
Addresses scanned: none
Datasheet:
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
Author: Ben Gardner <bgardner@wabtec.com>
Description
-----------
The Philips PCA9539 is a 16 bit low power I/O device.
All 16 lines can be individually configured as an input or output.
The input sense can also be inverted.
The 16 lines are split between two bytes.
Detection
---------
The PCA9539 is difficult to detect and not commonly found in PC machines,
so you have to pass the I2C bus and address of the installed PCA9539
devices explicitly to the driver at load time via the force=... parameter.
Sysfs entries
-------------
Each is a byte that maps to the 8 I/O bits.
A '0' suffix is for bits 0-7, while '1' is for bits 8-15.
input[01] - read the current value
output[01] - sets the output value
direction[01] - direction of each bit: 1=input, 0=output
invert[01] - toggle the input bit sense
input reads the actual state of the line and is always available.
The direction defaults to input for all channels.
General Remarks
---------------
Note that each output, direction, and invert entry controls 8 lines.
You should use the read, modify, write sequence.
For example. to set output bit 0 of 1.
val=$(cat output0)
val=$(( $val | 1 ))
echo $val > output0
Kernel driver pcf8574
=====================
Supported chips:
* Philips PCF8574
Prefix: 'pcf8574'
Addresses scanned: none
Datasheet: Publicly available at the Philips Semiconductors website
http://www.semiconductors.philips.com/pip/PCF8574P.html
* Philips PCF8574A
Prefix: 'pcf8574a'
Addresses scanned: none
Datasheet: Publicly available at the Philips Semiconductors website
http://www.semiconductors.philips.com/pip/PCF8574P.html
Authors:
Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Dan Eaton <dan.eaton@rocketlogix.com>,
Aurelien Jarno <aurelien@aurel32.net>,
Jean Delvare <khali@linux-fr.org>,
Description
-----------
The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips
Semiconductors. It is designed to provide a byte I2C interface to up to 16
separate devices (8 x PCF8574 and 8 x PCF8574A).
This device consists of a quasi-bidirectional port. Each of the eight I/Os
can be independently used as an input or output. To setup an I/O as an
input, you have to write a 1 to the corresponding output.
For more informations see the datasheet.
Accessing PCF8574(A) via /sys interface
-------------------------------------
The PCF8574(A) is plainly impossible to detect ! Stupid chip.
So, you have to pass the I2C bus and address of the installed PCF857A
and PCF8574A devices explicitly to the driver at load time via the
force=... parameter.
On detection (i.e. insmod, modprobe et al.), directories are being
created for each detected PCF8574(A):
/sys/bus/i2c/devices/<0>-<1>/
where <0> is the bus the chip was detected on (e. g. i2c-0)
and <1> the chip address ([20..27] or [38..3f]):
(example: /sys/bus/i2c/devices/1-0020/)
Inside these directories, there are two files each:
read and write (and one file with chip name).
The read file is read-only. Reading gives you the current I/O input
if the corresponding output is set as 1, otherwise the current output
value, that is to say 0.
The write file is read/write. Writing a value outputs it on the I/O
port. Reading returns the last written value. As it is not possible
to read this value from the chip, you need to write at least once to
this file before you can read back from it.
About the PCF8575 chip and the pcf8575 kernel driver
====================================================
The PCF8575 chip is produced by the following manufacturers:
* Philips NXP
http://www.nxp.com/#/pip/cb=[type=product,path=50807/41735/41850,final=PCF8575_3]|pip=[pip=PCF8575_3][0]
* Texas Instruments
http://focus.ti.com/docs/prod/folders/print/pcf8575.html
Some vendors sell small PCB's with the PCF8575 mounted on it. You can connect
such a board to a Linux host via e.g. an USB to I2C interface. Examples of
PCB boards with a PCF8575:
* SFE Breakout Board for PCF8575 I2C Expander by RobotShop
http://www.robotshop.ca/home/products/robot-parts/electronics/adapters-converters/sfe-pcf8575-i2c-expander-board.html
* Breakout Board for PCF8575 I2C Expander by Spark Fun Electronics
http://www.sparkfun.com/commerce/product_info.php?products_id=8130
Description
-----------
The PCF8575 chip is a 16-bit I/O expander for the I2C bus. Up to eight of
these chips can be connected to the same I2C bus. You can find this
chip on some custom designed hardware, but you won't find it on PC
motherboards.
The PCF8575 chip consists of a 16-bit quasi-bidirectional port and an I2C-bus
interface. Each of the sixteen I/O's can be independently used as an input or
an output. To set up an I/O pin as an input, you have to write a 1 to the
corresponding output.
For more information please see the datasheet.
Detection
---------
There is no method known to detect whether a chip on a given I2C address is
a PCF8575 or whether it is any other I2C device, so you have to pass the I2C
bus and address of the installed PCF8575 devices explicitly to the driver at
load time via the force=... parameter.
/sys interface
--------------
For each address on which a PCF8575 chip was found or forced the following
files will be created under /sys:
* /sys/bus/i2c/devices/<bus>-<address>/read
* /sys/bus/i2c/devices/<bus>-<address>/write
where bus is the I2C bus number (0, 1, ...) and address is the four-digit
hexadecimal representation of the 7-bit I2C address of the PCF8575
(0020 .. 0027).
The read file is read-only. Reading it will trigger an I2C read and will hence
report the current input state for the pins configured as inputs, and the
current output value for the pins configured as outputs.
The write file is read-write. Writing a value to it will configure all pins
as output for which the corresponding bit is zero. Reading the write file will
return the value last written, or -EAGAIN if no value has yet been written to
the write file.
On module initialization the configuration of the chip is not changed -- the
chip is left in the state it was already configured in through either power-up
or through previous I2C write actions.
...@@ -895,6 +895,13 @@ F: drivers/dma/ ...@@ -895,6 +895,13 @@ F: drivers/dma/
F: include/linux/dmaengine.h F: include/linux/dmaengine.h
F: include/linux/async_tx.h F: include/linux/async_tx.h
AT24 EEPROM DRIVER
M: Wolfram Sang <w.sang@pengutronix.de>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/misc/eeprom/at24.c
F: include/linux/i2c/at24.h
ATA OVER ETHERNET (AOE) DRIVER ATA OVER ETHERNET (AOE) DRIVER
M: "Ed L. Cashin" <ecashin@coraid.com> M: "Ed L. Cashin" <ecashin@coraid.com>
W: http://www.coraid.com/support/linux W: http://www.coraid.com/support/linux
...@@ -3964,6 +3971,15 @@ S: Maintained ...@@ -3964,6 +3971,15 @@ S: Maintained
F: drivers/leds/leds-pca9532.c F: drivers/leds/leds-pca9532.c
F: include/linux/leds-pca9532.h F: include/linux/leds-pca9532.h
PCA9564/PCA9665 I2C BUS DRIVER
M: Wolfram Sang <w.sang@pengutronix.de>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/algos/i2c-algo-pca.c
F: drivers/i2c/busses/i2c-pca-*
F: include/linux/i2c-algo-pca.h
F: include/linux/i2c-pca-platform.h
PCI ERROR RECOVERY PCI ERROR RECOVERY
M: Linas Vepstas <linas@austin.ibm.com> M: Linas Vepstas <linas@austin.ibm.com>
L: linux-pci@vger.kernel.org L: linux-pci@vger.kernel.org
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
static const struct i2c_device_id pcf857x_id[] = { static const struct i2c_device_id pcf857x_id[] = {
{ "pcf8574", 8 }, { "pcf8574", 8 },
{ "pcf8574a", 8 },
{ "pca8574", 8 }, { "pca8574", 8 },
{ "pca9670", 8 }, { "pca9670", 8 },
{ "pca9672", 8 }, { "pca9672", 8 },
......
...@@ -27,6 +27,14 @@ config I2C_BOARDINFO ...@@ -27,6 +27,14 @@ config I2C_BOARDINFO
boolean boolean
default y default y
config I2C_COMPAT
boolean "Enable compatibility bits for old user-space"
default y
help
Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
other user-space package which expects i2c adapters to be class
devices. If you don't know, say Y.
config I2C_CHARDEV config I2C_CHARDEV
tristate "I2C device interface" tristate "I2C device interface"
help help
......
...@@ -113,7 +113,7 @@ config I2C_ISCH ...@@ -113,7 +113,7 @@ config I2C_ISCH
will be called i2c-isch. will be called i2c-isch.
config I2C_PIIX4 config I2C_PIIX4
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
depends on PCI depends on PCI
help help
If you say yes to this option, support will be included for the Intel If you say yes to this option, support will be included for the Intel
...@@ -128,6 +128,7 @@ config I2C_PIIX4 ...@@ -128,6 +128,7 @@ config I2C_PIIX4
ATI SB600 ATI SB600
ATI SB700 ATI SB700
ATI SB800 ATI SB800
AMD SB900
Serverworks OSB4 Serverworks OSB4
Serverworks CSB5 Serverworks CSB5
Serverworks CSB6 Serverworks CSB6
...@@ -231,6 +232,22 @@ config I2C_VIAPRO ...@@ -231,6 +232,22 @@ config I2C_VIAPRO
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-viapro. will be called i2c-viapro.
if ACPI
comment "ACPI drivers"
config I2C_SCMI
tristate "SMBus Control Method Interface"
help
This driver supports the SMBus Control Method Interface. It needs the
BIOS to declare ACPI control methods as described in the SMBus Control
Method Interface specification.
To compile this driver as a module, choose M here:
the module will be called i2c-scmi.
endif # ACPI
comment "Mac SMBus host controller drivers" comment "Mac SMBus host controller drivers"
depends on PPC_CHRP || PPC_PMAC depends on PPC_CHRP || PPC_PMAC
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
# Makefile for the i2c bus drivers. # Makefile for the i2c bus drivers.
# #
# ACPI drivers
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
# PC SMBus host controller drivers # PC SMBus host controller drivers
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
Intel PIIX4, 440MX Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
AMD SB900
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.
...@@ -479,6 +480,7 @@ static struct pci_device_id piix4_ids[] = { ...@@ -479,6 +480,7 @@ static struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) }, PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
...@@ -499,9 +501,10 @@ static int __devinit piix4_probe(struct pci_dev *dev, ...@@ -499,9 +501,10 @@ static int __devinit piix4_probe(struct pci_dev *dev,
{ {
int retval; int retval;
if ((dev->vendor == PCI_VENDOR_ID_ATI) && if ((dev->vendor == PCI_VENDOR_ID_ATI &&
(dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
(dev->revision >= 0x40)) dev->revision >= 0x40) ||
dev->vendor == PCI_VENDOR_ID_AMD)
/* base address location etc changed in SB800 */ /* base address location etc changed in SB800 */
retval = piix4_setup_sb800(dev, id); retval = piix4_setup_sb800(dev, id);
else else
......
...@@ -586,7 +586,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) ...@@ -586,7 +586,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
/* Register I/O resource */ /* Register I/O resource */
if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) { if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE,
pdev->name)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n", "I/O region 0x%08x for I2C already in use.\n",
alg_data->base); alg_data->base);
...@@ -650,7 +651,7 @@ out_clock: ...@@ -650,7 +651,7 @@ out_clock:
out_unmap: out_unmap:
iounmap((void *)alg_data->ioaddr); iounmap((void *)alg_data->ioaddr);
out_release: out_release:
release_region(alg_data->base, I2C_PNX_REGION_SIZE); release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
out_drvdata: out_drvdata:
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
out: out:
...@@ -667,7 +668,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) ...@@ -667,7 +668,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
i2c_del_adapter(adap); i2c_del_adapter(adap);
i2c_pnx->set_clock_stop(pdev); i2c_pnx->set_clock_stop(pdev);
iounmap((void *)alg_data->ioaddr); iounmap((void *)alg_data->ioaddr);
release_region(alg_data->base, I2C_PNX_REGION_SIZE); release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
return 0; return 0;
......
/*
* SMBus driver for ACPI SMBus CMI
*
* Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
*
* 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.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#define ACPI_SMBUS_HC_CLASS "smbus"
#define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
ACPI_MODULE_NAME("smbus_cmi");
struct smbus_methods_t {
char *mt_info;
char *mt_sbr;
char *mt_sbw;
};
struct acpi_smbus_cmi {
acpi_handle handle;
struct i2c_adapter adapter;
u8 cap_info:1;
u8 cap_read:1;
u8 cap_write:1;
};
static const struct smbus_methods_t smbus_methods = {
.mt_info = "_SBI",
.mt_sbr = "_SBR",
.mt_sbw = "_SBW",
};
static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
{"SMBUS01", 0},
{"", 0}
};
#define ACPI_SMBUS_STATUS_OK 0x00
#define ACPI_SMBUS_STATUS_FAIL 0x07
#define ACPI_SMBUS_STATUS_DNAK 0x10
#define ACPI_SMBUS_STATUS_DERR 0x11
#define ACPI_SMBUS_STATUS_CMD_DENY 0x12
#define ACPI_SMBUS_STATUS_UNKNOWN 0x13
#define ACPI_SMBUS_STATUS_ACC_DENY 0x17
#define ACPI_SMBUS_STATUS_TIMEOUT 0x18
#define ACPI_SMBUS_STATUS_NOTSUP 0x19
#define ACPI_SMBUS_STATUS_BUSY 0x1a
#define ACPI_SMBUS_STATUS_PEC 0x1f
#define ACPI_SMBUS_PRTCL_WRITE 0x00
#define ACPI_SMBUS_PRTCL_READ 0x01
#define ACPI_SMBUS_PRTCL_QUICK 0x02
#define ACPI_SMBUS_PRTCL_BYTE 0x04
#define ACPI_SMBUS_PRTCL_BYTE_DATA 0x06
#define ACPI_SMBUS_PRTCL_WORD_DATA 0x08
#define ACPI_SMBUS_PRTCL_BLOCK_DATA 0x0a
static int
acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data *data)
{
int result = 0;
struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
unsigned char protocol;
acpi_status status = 0;
struct acpi_object_list input;
union acpi_object mt_params[5];
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
union acpi_object *pkg;
char *method;
int len = 0;
dev_dbg(&adap->dev, "access size: %d %s\n", size,
(read_write) ? "READ" : "WRITE");
switch (size) {
case I2C_SMBUS_QUICK:
protocol = ACPI_SMBUS_PRTCL_QUICK;
command = 0;
if (read_write == I2C_SMBUS_WRITE) {
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = 0;
mt_params[4].type = ACPI_TYPE_INTEGER;
mt_params[4].integer.value = 0;
}
break;
case I2C_SMBUS_BYTE:
protocol = ACPI_SMBUS_PRTCL_BYTE;
if (read_write == I2C_SMBUS_WRITE) {
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = 0;
mt_params[4].type = ACPI_TYPE_INTEGER;
mt_params[4].integer.value = 0;
} else {
command = 0;
}
break;
case I2C_SMBUS_BYTE_DATA:
protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
if (read_write == I2C_SMBUS_WRITE) {
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = 1;
mt_params[4].type = ACPI_TYPE_INTEGER;
mt_params[4].integer.value = data->byte;
}
break;
case I2C_SMBUS_WORD_DATA:
protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
if (read_write == I2C_SMBUS_WRITE) {
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = 2;
mt_params[4].type = ACPI_TYPE_INTEGER;
mt_params[4].integer.value = data->word;
}
break;
case I2C_SMBUS_BLOCK_DATA:
protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL;
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = len;
mt_params[4].type = ACPI_TYPE_BUFFER;
mt_params[4].buffer.pointer = data->block + 1;
}
break;
default:
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
if (read_write == I2C_SMBUS_READ) {
protocol |= ACPI_SMBUS_PRTCL_READ;
method = smbus_methods.mt_sbr;
input.count = 3;
} else {
protocol |= ACPI_SMBUS_PRTCL_WRITE;
method = smbus_methods.mt_sbw;
input.count = 5;
}
input.pointer = mt_params;
mt_params[0].type = ACPI_TYPE_INTEGER;
mt_params[0].integer.value = protocol;
mt_params[1].type = ACPI_TYPE_INTEGER;
mt_params[1].integer.value = addr;
mt_params[2].type = ACPI_TYPE_INTEGER;
mt_params[2].integer.value = command;
status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
&buffer);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status));
return -EIO;
}
pkg = buffer.pointer;
if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
obj = pkg->package.elements;
else {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
result = -EIO;
goto out;
}
if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
result = -EIO;
goto out;
}
result = obj->integer.value;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n",
method, result));
switch (result) {
case ACPI_SMBUS_STATUS_OK:
result = 0;
break;
case ACPI_SMBUS_STATUS_BUSY:
result = -EBUSY;
goto out;
case ACPI_SMBUS_STATUS_TIMEOUT:
result = -ETIMEDOUT;
goto out;
case ACPI_SMBUS_STATUS_DNAK:
result = -ENXIO;
goto out;
default:
result = -EIO;
goto out;
}
if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
goto out;
obj = pkg->package.elements + 1;
if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
result = -EIO;
goto out;
}
len = obj->integer.value;
obj = pkg->package.elements + 2;
switch (size) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
case I2C_SMBUS_WORD_DATA:
if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
result = -EIO;
goto out;
}
if (len == 2)
data->word = obj->integer.value;
else
data->byte = obj->integer.value;
break;
case I2C_SMBUS_BLOCK_DATA:
if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
result = -EIO;
goto out;
}
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
data->block[0] = len;
memcpy(data->block + 1, obj->buffer.pointer, len);
break;
}
out:
kfree(buffer.pointer);
dev_dbg(&adap->dev, "Transaction status: %i\n", result);
return result;
}
static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
{
struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
u32 ret;
ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
I2C_FUNC_SMBUS_QUICK : 0;
ret |= smbus_cmi->cap_read ?
(I2C_FUNC_SMBUS_READ_BYTE |
I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
ret |= smbus_cmi->cap_write ?
(I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
return ret;
}
static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
.smbus_xfer = acpi_smbus_cmi_access,
.functionality = acpi_smbus_cmi_func,
};
static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
const char *name)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
if (!strcmp(name, smbus_methods.mt_info)) {
status = acpi_evaluate_object(smbus_cmi->handle,
smbus_methods.mt_info,
NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
smbus_methods.mt_info, status));
return -EIO;
}
obj = buffer.pointer;
if (obj && obj->type == ACPI_TYPE_PACKAGE)
obj = obj->package.elements;
else {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
kfree(buffer.pointer);
return -EIO;
}
if (obj->type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO, "Invalid argument type"));
kfree(buffer.pointer);
return -EIO;
} else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x"
"\n", (int)obj->integer.value));
kfree(buffer.pointer);
smbus_cmi->cap_info = 1;
} else if (!strcmp(name, smbus_methods.mt_sbr))
smbus_cmi->cap_read = 1;
else if (!strcmp(name, smbus_methods.mt_sbw))
smbus_cmi->cap_write = 1;
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
name));
return 0;
}
static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
void *context, void **return_value)
{
char node_name[5];
struct acpi_buffer buffer = { sizeof(node_name), node_name };
struct acpi_smbus_cmi *smbus_cmi = context;
acpi_status status;
status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
if (ACPI_SUCCESS(status))
acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
return AE_OK;
}
static int acpi_smbus_cmi_add(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi)
return -ENOMEM;
smbus_cmi->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
device->driver_data = smbus_cmi;
smbus_cmi->cap_info = 0;
smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 0;
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, smbus_cmi, NULL);
if (smbus_cmi->cap_info == 0)
goto err;
snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
"SMBus CMI adapter %s (%s)",
acpi_device_name(device),
acpi_device_uid(device));
smbus_cmi->adapter.owner = THIS_MODULE;
smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
smbus_cmi->adapter.algo_data = smbus_cmi;
smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
smbus_cmi->adapter.dev.parent = &device->dev;
if (i2c_add_adapter(&smbus_cmi->adapter)) {
dev_err(&device->dev, "Couldn't register adapter!\n");
goto err;
}
return 0;
err:
kfree(smbus_cmi);
device->driver_data = NULL;
return -EIO;
}
static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
{
struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
i2c_del_adapter(&smbus_cmi->adapter);
kfree(smbus_cmi);
device->driver_data = NULL;
return 0;
}
static struct acpi_driver acpi_smbus_cmi_driver = {
.name = ACPI_SMBUS_HC_DEVICE_NAME,
.class = ACPI_SMBUS_HC_CLASS,
.ids = acpi_smbus_cmi_ids,
.ops = {
.add = acpi_smbus_cmi_add,
.remove = acpi_smbus_cmi_remove,
},
};
static int __init acpi_smbus_cmi_init(void)
{
return acpi_bus_register_driver(&acpi_smbus_cmi_driver);
}
static void __exit acpi_smbus_cmi_exit(void)
{
acpi_bus_unregister_driver(&acpi_smbus_cmi_driver);
}
module_init(acpi_smbus_cmi_init);
module_exit(acpi_smbus_cmi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
MODULE_DESCRIPTION("ACPI SMBus CMI driver");
...@@ -32,10 +32,12 @@ ...@@ -32,10 +32,12 @@
#define TAOS_STATE_INIT 0 #define TAOS_STATE_INIT 0
#define TAOS_STATE_IDLE 1 #define TAOS_STATE_IDLE 1
#define TAOS_STATE_SEND 2 #define TAOS_STATE_EOFF 2
#define TAOS_STATE_RECV 3 #define TAOS_STATE_RECV 3
#define TAOS_CMD_RESET 0x12 #define TAOS_CMD_RESET 0x12
#define TAOS_CMD_ECHO_ON '+'
#define TAOS_CMD_ECHO_OFF '-'
static DECLARE_WAIT_QUEUE_HEAD(wq); static DECLARE_WAIT_QUEUE_HEAD(wq);
...@@ -102,17 +104,9 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -102,17 +104,9 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
/* Send the transaction to the TAOS EVM */ /* Send the transaction to the TAOS EVM */
dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer); dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
taos->pos = 0; for (p = taos->buffer; *p; p++)
taos->state = TAOS_STATE_SEND; serio_write(serio, *p);
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; taos->addr = addr;
/* Start the transaction and read the answer */ /* Start the transaction and read the answer */
...@@ -122,7 +116,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -122,7 +116,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE, wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(150)); msecs_to_jiffies(150));
if (taos->state != TAOS_STATE_IDLE if (taos->state != TAOS_STATE_IDLE
|| taos->pos != 6) { || taos->pos != 5) {
dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n", dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
taos->pos); taos->pos);
return -EIO; return -EIO;
...@@ -130,7 +124,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -130,7 +124,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer); dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
/* Interpret the returned string */ /* Interpret the returned string */
p = taos->buffer + 2; p = taos->buffer + 1;
p[3] = '\0'; p[3] = '\0';
if (!strcmp(p, "NAK")) if (!strcmp(p, "NAK"))
return -ENODEV; return -ENODEV;
...@@ -173,13 +167,9 @@ static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data, ...@@ -173,13 +167,9 @@ static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
wake_up_interruptible(&wq); wake_up_interruptible(&wq);
} }
break; break;
case TAOS_STATE_SEND: case TAOS_STATE_EOFF:
if (taos->buffer[++taos->pos]) taos->state = TAOS_STATE_IDLE;
serio_write(serio, taos->buffer[taos->pos]); wake_up_interruptible(&wq);
else {
taos->state = TAOS_STATE_IDLE;
wake_up_interruptible(&wq);
}
break; break;
case TAOS_STATE_RECV: case TAOS_STATE_RECV:
taos->buffer[taos->pos++] = data; taos->buffer[taos->pos++] = data;
...@@ -257,6 +247,19 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) ...@@ -257,6 +247,19 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
} }
strlcpy(adapter->name, name, sizeof(adapter->name)); strlcpy(adapter->name, name, sizeof(adapter->name));
/* Turn echo off for better performance */
taos->state = TAOS_STATE_EOFF;
serio_write(serio, TAOS_CMD_ECHO_OFF);
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(250));
if (taos->state != TAOS_STATE_IDLE) {
err = -ENODEV;
dev_err(&adapter->dev, "Echo off failed "
"(state=%d)\n", taos->state);
goto exit_close;
}
err = i2c_add_adapter(adapter); err = i2c_add_adapter(adapter);
if (err) if (err)
goto exit_close; goto exit_close;
......
...@@ -217,8 +217,10 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) ...@@ -217,8 +217,10 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
return; return;
error: error:
dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg, dev_err(&iface->adapter.dev,
scx200_acb_state_name[iface->state]); "%s in state %s (addr=0x%02x, len=%d, status=0x%02x)\n", errmsg,
scx200_acb_state_name[iface->state], iface->address_byte,
iface->len, status);
iface->state = state_idle; iface->state = state_idle;
iface->result = -EIO; iface->result = -EIO;
......
...@@ -16,54 +16,6 @@ config DS1682 ...@@ -16,54 +16,6 @@ config DS1682
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 ds1682. will be called ds1682.
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A (DEPRECATED)"
depends on EXPERIMENTAL && GPIO_PCF857X = "n"
default n
help
If you say yes here you get support for Philips PCF8574 and
PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
This driver can also be built as a module. If so, the module
will be called pcf8574.
This driver is deprecated and will be dropped soon. Use
drivers/gpio/pcf857x.c instead.
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
config PCF8575
tristate "Philips PCF8575 (DEPRECATED)"
default n
depends on GPIO_PCF857X = "n"
help
If you say yes here you get support for Philips PCF8575 chip.
This chip is a 16-bit I/O expander for the I2C bus. Several other
chip manufacturers sell equivalent chips, e.g. Texas Instruments.
This driver can also be built as a module. If so, the module
will be called pcf8575.
This driver is deprecated and will be dropped soon. Use
drivers/gpio/pcf857x.c instead.
This device is hard to detect and is rarely found on mainstream
hardware. If unsure, say N.
config SENSORS_PCA9539
tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)"
depends on EXPERIMENTAL && GPIO_PCA953X = "n"
help
If you say yes here you get support for the Philips PCA9539
16-bit I/O port.
This driver can also be built as a module. If so, the module
will be called pca9539.
This driver is deprecated and will be dropped soon. Use
drivers/gpio/pca953x.c instead.
config SENSORS_TSL2550 config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor" tristate "Taos TSL2550 ambient light sensor"
depends on EXPERIMENTAL depends on EXPERIMENTAL
......
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
# #
obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_PCF8575) += pcf8575.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
......
/*
pca9539.c - 16-bit I/O port with interrupt and reset
Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>
/* Addresses to scan: none, device is not autodetected */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(pca9539);
enum pca9539_cmd
{
PCA9539_INPUT_0 = 0,
PCA9539_INPUT_1 = 1,
PCA9539_OUTPUT_0 = 2,
PCA9539_OUTPUT_1 = 3,
PCA9539_INVERT_0 = 4,
PCA9539_INVERT_1 = 5,
PCA9539_DIRECTION_0 = 6,
PCA9539_DIRECTION_1 = 7,
};
/* following are the sysfs callback functions */
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
struct i2c_client *client = to_i2c_client(dev);
return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client,
psa->index));
}
static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
struct i2c_client *client = to_i2c_client(dev);
unsigned long val = simple_strtoul(buf, NULL, 0);
if (val > 0xff)
return -EINVAL;
i2c_smbus_write_byte_data(client, psa->index, val);
return count;
}
/* Define the device attributes */
#define PCA9539_ENTRY_RO(name, cmd_idx) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx)
#define PCA9539_ENTRY_RW(name, cmd_idx) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \
pca9539_store, cmd_idx)
PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0);
PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1);
PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0);
PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1);
PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0);
PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1);
PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0);
PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1);
static struct attribute *pca9539_attributes[] = {
&sensor_dev_attr_input0.dev_attr.attr,
&sensor_dev_attr_input1.dev_attr.attr,
&sensor_dev_attr_output0.dev_attr.attr,
&sensor_dev_attr_output1.dev_attr.attr,
&sensor_dev_attr_invert0.dev_attr.attr,
&sensor_dev_attr_invert1.dev_attr.attr,
&sensor_dev_attr_direction0.dev_attr.attr,
&sensor_dev_attr_direction1.dev_attr.attr,
NULL
};
static struct attribute_group pca9539_defattr_group = {
.attrs = pca9539_attributes,
};
/* Return 0 if detection is successful, -ENODEV otherwise */
static int pca9539_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
strlcpy(info->type, "pca9539", I2C_NAME_SIZE);
return 0;
}
static int pca9539_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
/* Register sysfs hooks */
return sysfs_create_group(&client->dev.kobj,
&pca9539_defattr_group);
}
static int pca9539_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
return 0;
}
static const struct i2c_device_id pca9539_id[] = {
{ "pca9539", 0 },
{ }
};
static struct i2c_driver pca9539_driver = {
.driver = {
.name = "pca9539",
},
.probe = pca9539_probe,
.remove = pca9539_remove,
.id_table = pca9539_id,
.detect = pca9539_detect,
.address_data = &addr_data,
};
static int __init pca9539_init(void)
{
return i2c_add_driver(&pca9539_driver);
}
static void __exit pca9539_exit(void)
{
i2c_del_driver(&pca9539_driver);
}
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
MODULE_DESCRIPTION("PCA9539 driver");
MODULE_LICENSE("GPL");
module_init(pca9539_init);
module_exit(pca9539_exit);
/*
Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Dan Eaton <dan.eaton@rocketlogix.com>
Ported to Linux 2.6 by Aurelien Jarno <aurel32@debian.org> with
the help of Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A few notes about the PCF8574:
* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by
Philips Semiconductors. It is designed to provide a byte I2C
interface to up to 8 separate devices.
* The PCF8574 appears as a very simple SMBus device which can be
read from or written to with SMBUS byte read/write accesses.
--Dan
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
/* Addresses to scan: none, device can't be detected */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
/* Each client has this additional data */
struct pcf8574_data {
int write; /* Remember last written value */
};
static void pcf8574_init_client(struct i2c_client *client);
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
return sprintf(buf, "%u\n", i2c_smbus_read_byte(client));
}
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
if (data->write < 0)
return data->write;
return sprintf(buf, "%d\n", data->write);
}
static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8574_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
if (val > 0xff)
return -EINVAL;
data->write = val;
i2c_smbus_write_byte(client, data->write);
return count;
}
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
static struct attribute *pcf8574_attributes[] = {
&dev_attr_read.attr,
&dev_attr_write.attr,
NULL
};
static const struct attribute_group pcf8574_attr_group = {
.attrs = pcf8574_attributes,
};
/*
* Real code
*/
/* Return 0 if detection is successful, -ENODEV otherwise */
static int pcf8574_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
const char *client_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
/* Now, we would do the remaining detection. But the PCF8574 is plainly
impossible to detect! Stupid chip. */
/* Determine the chip type */
if (kind <= 0) {
if (client->addr >= 0x38 && client->addr <= 0x3f)
kind = pcf8574a;
else
kind = pcf8574;
}
if (kind == pcf8574a)
client_name = "pcf8574a";
else
client_name = "pcf8574";
strlcpy(info->type, client_name, I2C_NAME_SIZE);
return 0;
}
static int pcf8574_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf8574_data *data;
int err;
data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
/* Initialize the PCF8574 chip */
pcf8574_init_client(client);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group);
if (err)
goto exit_free;
return 0;
exit_free:
kfree(data);
exit:
return err;
}
static int pcf8574_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
kfree(i2c_get_clientdata(client));
return 0;
}
/* Called when we have found a new PCF8574. */
static void pcf8574_init_client(struct i2c_client *client)
{
struct pcf8574_data *data = i2c_get_clientdata(client);
data->write = -EAGAIN;
}
static const struct i2c_device_id pcf8574_id[] = {
{ "pcf8574", 0 },
{ "pcf8574a", 0 },
{ }
};
static struct i2c_driver pcf8574_driver = {
.driver = {
.name = "pcf8574",
},
.probe = pcf8574_probe,
.remove = pcf8574_remove,
.id_table = pcf8574_id,
.detect = pcf8574_detect,
.address_data = &addr_data,
};
static int __init pcf8574_init(void)
{
return i2c_add_driver(&pcf8574_driver);
}
static void __exit pcf8574_exit(void)
{
i2c_del_driver(&pcf8574_driver);
}
MODULE_AUTHOR
("Frodo Looijaard <frodol@dds.nl>, "
"Philip Edelbrock <phil@netroedge.com>, "
"Dan Eaton <dan.eaton@rocketlogix.com> "
"and Aurelien Jarno <aurelien@aurel32.net>");
MODULE_DESCRIPTION("PCF8574 driver");
MODULE_LICENSE("GPL");
module_init(pcf8574_init);
module_exit(pcf8574_exit);
/*
pcf8575.c
About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
produced by a.o. Philips Semiconductors.
Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
<hennerich@blackfin.uclinux.org>
Based on pcf8574.c.
Copyright (c) 2007 Bart Van Assche <bart.vanassche@gmail.com>.
Ported this driver from ucLinux to the mainstream Linux kernel.
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/i2c.h>
#include <linux/slab.h> /* kzalloc() */
#include <linux/sysfs.h> /* sysfs_create_group() */
/* Addresses to scan: none, device can't be detected */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD;
/* Each client has this additional data */
struct pcf8575_data {
int write; /* last written value, or error code */
};
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
u16 val;
u8 iopin_state[2];
i2c_master_recv(client, iopin_state, 2);
val = iopin_state[0];
val |= iopin_state[1] << 8;
return sprintf(buf, "%u\n", val);
}
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
static ssize_t show_write(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pcf8575_data *data = dev_get_drvdata(dev);
if (data->write < 0)
return data->write;
return sprintf(buf, "%d\n", data->write);
}
static ssize_t set_write(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pcf8575_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
u8 iopin_state[2];
if (val > 0xffff)
return -EINVAL;
data->write = val;
iopin_state[0] = val & 0xFF;
iopin_state[1] = val >> 8;
i2c_master_send(client, iopin_state, 2);
return count;
}
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
static struct attribute *pcf8575_attributes[] = {
&dev_attr_read.attr,
&dev_attr_write.attr,
NULL
};
static const struct attribute_group pcf8575_attr_group = {
.attrs = pcf8575_attributes,
};
/*
* Real code
*/
/* Return 0 if detection is successful, -ENODEV otherwise */
static int pcf8575_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -ENODEV;
/* This is the place to detect whether the chip at the specified
address really is a PCF8575 chip. However, there is no method known
to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
strlcpy(info->type, "pcf8575", I2C_NAME_SIZE);
return 0;
}
static int pcf8575_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf8575_data *data;
int err;
data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->write = -EAGAIN;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
if (err)
goto exit_free;
return 0;
exit_free:
kfree(data);
exit:
return err;
}
static int pcf8575_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
kfree(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id pcf8575_id[] = {
{ "pcf8575", 0 },
{ }
};
static struct i2c_driver pcf8575_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pcf8575",
},
.probe = pcf8575_probe,
.remove = pcf8575_remove,
.id_table = pcf8575_id,
.detect = pcf8575_detect,
.address_data = &addr_data,
};
static int __init pcf8575_init(void)
{
return i2c_add_driver(&pcf8575_driver);
}
static void __exit pcf8575_exit(void)
{
i2c_del_driver(&pcf8575_driver);
}
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>, "
"Bart Van Assche <bart.vanassche@gmail.com>");
MODULE_DESCRIPTION("pcf8575 driver");
MODULE_LICENSE("GPL");
module_init(pcf8575_init);
module_exit(pcf8575_exit);
...@@ -24,10 +24,9 @@ ...@@ -24,10 +24,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/delay.h>
#define TSL2550_DRV_NAME "tsl2550" #define TSL2550_DRV_NAME "tsl2550"
#define DRIVER_VERSION "1.1.2" #define DRIVER_VERSION "1.2"
/* /*
* Defines * Defines
...@@ -96,32 +95,13 @@ static int tsl2550_set_power_state(struct i2c_client *client, int state) ...@@ -96,32 +95,13 @@ static int tsl2550_set_power_state(struct i2c_client *client, int state)
static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd) static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
{ {
unsigned long end; int ret;
int loop = 0, ret = 0;
/* ret = i2c_smbus_read_byte_data(client, cmd);
* Read ADC channel waiting at most 400ms (see data sheet for further if (ret < 0)
* info). return ret;
* 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)) if (!(ret & 0x80))
return -EIO; return -EAGAIN;
return ret & 0x7f; /* remove the "valid" bit */ return ret & 0x7f; /* remove the "valid" bit */
} }
...@@ -285,8 +265,6 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) ...@@ -285,8 +265,6 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
return ret; return ret;
ch0 = ret; ch0 = ret;
mdelay(1);
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1); ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -345,11 +323,10 @@ static int tsl2550_init_client(struct i2c_client *client) ...@@ -345,11 +323,10 @@ static int tsl2550_init_client(struct i2c_client *client)
* Probe the chip. To do so we try to power up the device and then to * Probe the chip. To do so we try to power up the device and then to
* read back the 0x03 code * read back the 0x03 code
*/ */
err = i2c_smbus_write_byte(client, TSL2550_POWER_UP); err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
if (err < 0) if (err < 0)
return err; return err;
mdelay(1); if (err != TSL2550_POWER_UP)
if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
return -ENODEV; return -ENODEV;
data->power_state = 1; data->power_state = 1;
...@@ -374,7 +351,8 @@ static int __devinit tsl2550_probe(struct i2c_client *client, ...@@ -374,7 +351,8 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
struct tsl2550_data *data; struct tsl2550_data *data;
int *opmode, err = 0; int *opmode, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
| I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
err = -EIO; err = -EIO;
goto exit; goto exit;
} }
......
...@@ -46,6 +46,7 @@ static DEFINE_MUTEX(core_lock); ...@@ -46,6 +46,7 @@ static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr); static DEFINE_IDR(i2c_adapter_idr);
static LIST_HEAD(userspace_devices); static LIST_HEAD(userspace_devices);
static struct device_type i2c_client_type;
static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_check_addr(struct i2c_adapter *adapter, int addr);
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
...@@ -64,9 +65,13 @@ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, ...@@ -64,9 +65,13 @@ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
static int i2c_device_match(struct device *dev, struct device_driver *drv) static int i2c_device_match(struct device *dev, struct device_driver *drv)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver = to_i2c_driver(drv); struct i2c_driver *driver;
if (!client)
return 0;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */ /* match on an id table if there is one */
if (driver->id_table) if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL; return i2c_match_id(driver->id_table, client) != NULL;
...@@ -94,10 +99,14 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -94,10 +99,14 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
static int i2c_device_probe(struct device *dev) static int i2c_device_probe(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver = to_i2c_driver(dev->driver); struct i2c_driver *driver;
int status; int status;
if (!client)
return 0;
driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table) if (!driver->probe || !driver->id_table)
return -ENODEV; return -ENODEV;
client->driver = driver; client->driver = driver;
...@@ -114,11 +123,11 @@ static int i2c_device_probe(struct device *dev) ...@@ -114,11 +123,11 @@ static int i2c_device_probe(struct device *dev)
static int i2c_device_remove(struct device *dev) static int i2c_device_remove(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver; struct i2c_driver *driver;
int status; int status;
if (!dev->driver) if (!client || !dev->driver)
return 0; return 0;
driver = to_i2c_driver(dev->driver); driver = to_i2c_driver(dev->driver);
...@@ -136,37 +145,40 @@ static int i2c_device_remove(struct device *dev) ...@@ -136,37 +145,40 @@ static int i2c_device_remove(struct device *dev)
static void i2c_device_shutdown(struct device *dev) static void i2c_device_shutdown(struct device *dev)
{ {
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver; struct i2c_driver *driver;
if (!dev->driver) if (!client || !dev->driver)
return; return;
driver = to_i2c_driver(dev->driver); driver = to_i2c_driver(dev->driver);
if (driver->shutdown) if (driver->shutdown)
driver->shutdown(to_i2c_client(dev)); driver->shutdown(client);
} }
static int i2c_device_suspend(struct device *dev, pm_message_t mesg) static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
{ {
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver; struct i2c_driver *driver;
if (!dev->driver) if (!client || !dev->driver)
return 0; return 0;
driver = to_i2c_driver(dev->driver); driver = to_i2c_driver(dev->driver);
if (!driver->suspend) if (!driver->suspend)
return 0; return 0;
return driver->suspend(to_i2c_client(dev), mesg); return driver->suspend(client, mesg);
} }
static int i2c_device_resume(struct device *dev) static int i2c_device_resume(struct device *dev)
{ {
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver; struct i2c_driver *driver;
if (!dev->driver) if (!client || !dev->driver)
return 0; return 0;
driver = to_i2c_driver(dev->driver); driver = to_i2c_driver(dev->driver);
if (!driver->resume) if (!driver->resume)
return 0; return 0;
return driver->resume(to_i2c_client(dev)); return driver->resume(client);
} }
static void i2c_client_dev_release(struct device *dev) static void i2c_client_dev_release(struct device *dev)
...@@ -175,10 +187,10 @@ static void i2c_client_dev_release(struct device *dev) ...@@ -175,10 +187,10 @@ static void i2c_client_dev_release(struct device *dev)
} }
static ssize_t static ssize_t
show_client_name(struct device *dev, struct device_attribute *attr, char *buf) show_name(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct i2c_client *client = to_i2c_client(dev); return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
return sprintf(buf, "%s\n", client->name); to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
} }
static ssize_t static ssize_t
...@@ -188,18 +200,28 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -188,18 +200,28 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
} }
static struct device_attribute i2c_dev_attrs[] = { static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
__ATTR(name, S_IRUGO, show_client_name, NULL), static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
static struct attribute *i2c_dev_attrs[] = {
&dev_attr_name.attr,
/* modalias helps coldplug: modprobe $(cat .../modalias) */ /* modalias helps coldplug: modprobe $(cat .../modalias) */
__ATTR(modalias, S_IRUGO, show_modalias, NULL), &dev_attr_modalias.attr,
{ }, NULL
};
static struct attribute_group i2c_dev_attr_group = {
.attrs = i2c_dev_attrs,
};
static const struct attribute_group *i2c_dev_attr_groups[] = {
&i2c_dev_attr_group,
NULL
}; };
struct bus_type i2c_bus_type = { struct bus_type i2c_bus_type = {
.name = "i2c", .name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match, .match = i2c_device_match,
.uevent = i2c_device_uevent,
.probe = i2c_device_probe, .probe = i2c_device_probe,
.remove = i2c_device_remove, .remove = i2c_device_remove,
.shutdown = i2c_device_shutdown, .shutdown = i2c_device_shutdown,
...@@ -208,6 +230,12 @@ struct bus_type i2c_bus_type = { ...@@ -208,6 +230,12 @@ struct bus_type i2c_bus_type = {
}; };
EXPORT_SYMBOL_GPL(i2c_bus_type); EXPORT_SYMBOL_GPL(i2c_bus_type);
static struct device_type i2c_client_type = {
.groups = i2c_dev_attr_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
/** /**
* i2c_verify_client - return parameter as i2c_client, or NULL * i2c_verify_client - return parameter as i2c_client, or NULL
...@@ -220,7 +248,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type); ...@@ -220,7 +248,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type);
*/ */
struct i2c_client *i2c_verify_client(struct device *dev) struct i2c_client *i2c_verify_client(struct device *dev)
{ {
return (dev->bus == &i2c_bus_type) return (dev->type == &i2c_client_type)
? to_i2c_client(dev) ? to_i2c_client(dev)
: NULL; : NULL;
} }
...@@ -273,7 +301,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) ...@@ -273,7 +301,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->dev.parent = &client->adapter->dev; client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type; client->dev.bus = &i2c_bus_type;
client->dev.release = i2c_client_dev_release; client->dev.type = &i2c_client_type;
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr); client->addr);
...@@ -368,13 +396,6 @@ static void i2c_adapter_dev_release(struct device *dev) ...@@ -368,13 +396,6 @@ static void i2c_adapter_dev_release(struct device *dev)
complete(&adap->dev_released); complete(&adap->dev_released);
} }
static ssize_t
show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
return sprintf(buf, "%s\n", adap->name);
}
/* /*
* Let users instantiate I2C devices through sysfs. This can be used when * Let users instantiate I2C devices through sysfs. This can be used when
* platform initialization code doesn't contain the proper data for * platform initialization code doesn't contain the proper data for
...@@ -493,19 +514,34 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, ...@@ -493,19 +514,34 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
return res; return res;
} }
static struct device_attribute i2c_adapter_attrs[] = { static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
__ATTR(name, S_IRUGO, show_adapter_name, NULL), static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
__ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device),
__ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device), static struct attribute *i2c_adapter_attrs[] = {
{ }, &dev_attr_name.attr,
&dev_attr_new_device.attr,
&dev_attr_delete_device.attr,
NULL
}; };
static struct class i2c_adapter_class = { static struct attribute_group i2c_adapter_attr_group = {
.owner = THIS_MODULE, .attrs = i2c_adapter_attrs,
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
}; };
static const struct attribute_group *i2c_adapter_attr_groups[] = {
&i2c_adapter_attr_group,
NULL
};
static struct device_type i2c_adapter_type = {
.groups = i2c_adapter_attr_groups,
.release = i2c_adapter_dev_release,
};
#ifdef CONFIG_I2C_COMPAT
static struct class_compat *i2c_adapter_compat_class;
#endif
static void i2c_scan_static_board_info(struct i2c_adapter *adapter) static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{ {
struct i2c_devinfo *devinfo; struct i2c_devinfo *devinfo;
...@@ -555,14 +591,22 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -555,14 +591,22 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
adap->timeout = HZ; adap->timeout = HZ;
dev_set_name(&adap->dev, "i2c-%d", adap->nr); dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.release = &i2c_adapter_dev_release; adap->dev.bus = &i2c_bus_type;
adap->dev.class = &i2c_adapter_class; adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev); res = device_register(&adap->dev);
if (res) if (res)
goto out_list; goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
/* create pre-declared device nodes */ /* create pre-declared device nodes */
if (adap->nr < __i2c_first_dynamic_bus_num) if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap); i2c_scan_static_board_info(adap);
...@@ -741,6 +785,11 @@ int i2c_del_adapter(struct i2c_adapter *adap) ...@@ -741,6 +785,11 @@ int i2c_del_adapter(struct i2c_adapter *adap)
checking the returned value. */ checking the returned value. */
res = device_for_each_child(&adap->dev, NULL, __unregister_client); res = device_for_each_child(&adap->dev, NULL, __unregister_client);
#ifdef CONFIG_I2C_COMPAT
class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
#endif
/* clean up the sysfs representation */ /* clean up the sysfs representation */
init_completion(&adap->dev_released); init_completion(&adap->dev_released);
device_unregister(&adap->dev); device_unregister(&adap->dev);
...@@ -768,9 +817,13 @@ EXPORT_SYMBOL(i2c_del_adapter); ...@@ -768,9 +817,13 @@ EXPORT_SYMBOL(i2c_del_adapter);
static int __attach_adapter(struct device *dev, void *data) static int __attach_adapter(struct device *dev, void *data)
{ {
struct i2c_adapter *adapter = to_i2c_adapter(dev); struct i2c_adapter *adapter;
struct i2c_driver *driver = data; struct i2c_driver *driver = data;
if (dev->type != &i2c_adapter_type)
return 0;
adapter = to_i2c_adapter(dev);
i2c_detect(adapter, driver); i2c_detect(adapter, driver);
/* Legacy drivers scan i2c busses directly */ /* Legacy drivers scan i2c busses directly */
...@@ -809,8 +862,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -809,8 +862,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
INIT_LIST_HEAD(&driver->clients); INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */ /* Walk the adapters that are already present */
mutex_lock(&core_lock); mutex_lock(&core_lock);
class_for_each_device(&i2c_adapter_class, NULL, driver, bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
__attach_adapter);
mutex_unlock(&core_lock); mutex_unlock(&core_lock);
return 0; return 0;
...@@ -819,10 +871,14 @@ EXPORT_SYMBOL(i2c_register_driver); ...@@ -819,10 +871,14 @@ EXPORT_SYMBOL(i2c_register_driver);
static int __detach_adapter(struct device *dev, void *data) static int __detach_adapter(struct device *dev, void *data)
{ {
struct i2c_adapter *adapter = to_i2c_adapter(dev); struct i2c_adapter *adapter;
struct i2c_driver *driver = data; struct i2c_driver *driver = data;
struct i2c_client *client, *_n; struct i2c_client *client, *_n;
if (dev->type != &i2c_adapter_type)
return 0;
adapter = to_i2c_adapter(dev);
/* Remove the devices we created ourselves as the result of hardware /* Remove the devices we created ourselves as the result of hardware
* probing (using a driver's detect method) */ * probing (using a driver's detect method) */
list_for_each_entry_safe(client, _n, &driver->clients, detected) { list_for_each_entry_safe(client, _n, &driver->clients, detected) {
...@@ -850,8 +906,7 @@ static int __detach_adapter(struct device *dev, void *data) ...@@ -850,8 +906,7 @@ static int __detach_adapter(struct device *dev, void *data)
void i2c_del_driver(struct i2c_driver *driver) void i2c_del_driver(struct i2c_driver *driver)
{ {
mutex_lock(&core_lock); mutex_lock(&core_lock);
class_for_each_device(&i2c_adapter_class, NULL, driver, bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
__detach_adapter);
mutex_unlock(&core_lock); mutex_unlock(&core_lock);
driver_unregister(&driver->driver); driver_unregister(&driver->driver);
...@@ -940,17 +995,23 @@ static int __init i2c_init(void) ...@@ -940,17 +995,23 @@ static int __init i2c_init(void)
retval = bus_register(&i2c_bus_type); retval = bus_register(&i2c_bus_type);
if (retval) if (retval)
return retval; return retval;
retval = class_register(&i2c_adapter_class); #ifdef CONFIG_I2C_COMPAT
if (retval) i2c_adapter_compat_class = class_compat_register("i2c-adapter");
if (!i2c_adapter_compat_class) {
retval = -ENOMEM;
goto bus_err; goto bus_err;
}
#endif
retval = i2c_add_driver(&dummy_driver); retval = i2c_add_driver(&dummy_driver);
if (retval) if (retval)
goto class_err; goto class_err;
return 0; return 0;
class_err: class_err:
class_unregister(&i2c_adapter_class); #ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
bus_err: bus_err:
#endif
bus_unregister(&i2c_bus_type); bus_unregister(&i2c_bus_type);
return retval; return retval;
} }
...@@ -958,7 +1019,9 @@ bus_err: ...@@ -958,7 +1019,9 @@ bus_err:
static void __exit i2c_exit(void) static void __exit i2c_exit(void)
{ {
i2c_del_driver(&dummy_driver); i2c_del_driver(&dummy_driver);
class_unregister(&i2c_adapter_class); #ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
#endif
bus_unregister(&i2c_bus_type); bus_unregister(&i2c_bus_type);
} }
......
...@@ -27,17 +27,6 @@ ...@@ -27,17 +27,6 @@
legacy chip driver needs to identify a bus or a bus driver needs to legacy chip driver needs to identify a bus or a bus driver needs to
identify a legacy client. If you don't need them, just don't set them. */ identify a legacy client. If you don't need them, just don't set them. */
/*
* ---- Driver types -----------------------------------------------------
*/
#define I2C_DRIVERID_MSP3400 1
#define I2C_DRIVERID_TUNER 2
#define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */
#define I2C_DRIVERID_TVAUDIO 29 /* Generic TV sound driver */
#define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */
#define I2C_DRIVERID_INFRARED 75 /* I2C InfraRed on Video boards */
/* /*
* ---- Adapter types ---------------------------------------------------- * ---- Adapter types ----------------------------------------------------
*/ */
......
...@@ -98,7 +98,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, ...@@ -98,7 +98,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
/** /**
* struct i2c_driver - represent an I2C device driver * struct i2c_driver - represent an I2C device driver
* @id: Unique driver ID (optional)
* @class: What kind of i2c device we instantiate (for detect) * @class: What kind of i2c device we instantiate (for detect)
* @attach_adapter: Callback for bus addition (for legacy drivers) * @attach_adapter: Callback for bus addition (for legacy drivers)
* @detach_adapter: Callback for bus removal (for legacy drivers) * @detach_adapter: Callback for bus removal (for legacy drivers)
...@@ -135,7 +134,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, ...@@ -135,7 +134,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
* not allowed. * not allowed.
*/ */
struct i2c_driver { struct i2c_driver {
int id;
unsigned int class; unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be /* Notifies the driver that a new bus has appeared or is about to be
......
...@@ -543,6 +543,7 @@ ...@@ -543,6 +543,7 @@
#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 #define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
#define PCI_DEVICE_ID_AMD_SB900_SMBUS 0x780b
#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F #define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F
#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment