mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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
This commit is contained in:
commit
40aba21896
@ -8,6 +8,8 @@ Supported adapters:
|
||||
Datasheet: Only available via NDA from ServerWorks
|
||||
* ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
|
||||
Datasheet: Not publicly available
|
||||
* AMD SB900
|
||||
Datasheet: Not publicly available
|
||||
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
|
||||
Datasheet: Publicly available at the SMSC website http://www.smsc.com
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
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
|
||||
|
@ -1,65 +0,0 @@
|
||||
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.
|
@ -1,69 +0,0 @@
|
||||
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.
|
16
MAINTAINERS
16
MAINTAINERS
@ -895,6 +895,13 @@ F: drivers/dma/
|
||||
F: include/linux/dmaengine.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
|
||||
M: "Ed L. Cashin" <ecashin@coraid.com>
|
||||
W: http://www.coraid.com/support/linux
|
||||
@ -3964,6 +3971,15 @@ S: Maintained
|
||||
F: drivers/leds/leds-pca9532.c
|
||||
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
|
||||
M: Linas Vepstas <linas@austin.ibm.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
static const struct i2c_device_id pcf857x_id[] = {
|
||||
{ "pcf8574", 8 },
|
||||
{ "pcf8574a", 8 },
|
||||
{ "pca8574", 8 },
|
||||
{ "pca9670", 8 },
|
||||
{ "pca9672", 8 },
|
||||
|
@ -27,6 +27,14 @@ config I2C_BOARDINFO
|
||||
boolean
|
||||
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
|
||||
tristate "I2C device interface"
|
||||
help
|
||||
|
@ -113,7 +113,7 @@ config I2C_ISCH
|
||||
will be called i2c-isch.
|
||||
|
||||
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
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
@ -128,6 +128,7 @@ config I2C_PIIX4
|
||||
ATI SB600
|
||||
ATI SB700
|
||||
ATI SB800
|
||||
AMD SB900
|
||||
Serverworks OSB4
|
||||
Serverworks CSB5
|
||||
Serverworks CSB6
|
||||
@ -231,6 +232,22 @@ config I2C_VIAPRO
|
||||
This driver can also be built as a module. If so, the module
|
||||
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"
|
||||
depends on PPC_CHRP || PPC_PMAC
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
# Makefile for the i2c bus drivers.
|
||||
#
|
||||
|
||||
# ACPI drivers
|
||||
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
|
||||
|
||||
# PC SMBus host controller drivers
|
||||
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
|
||||
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
|
||||
|
@ -22,6 +22,7 @@
|
||||
Intel PIIX4, 440MX
|
||||
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
|
||||
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
|
||||
AMD SB900
|
||||
SMSC Victory66
|
||||
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
@ -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_IXP400_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_ID_SERVERWORKS_OSB4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
|
||||
@ -499,9 +501,10 @@ static int __devinit piix4_probe(struct pci_dev *dev,
|
||||
{
|
||||
int retval;
|
||||
|
||||
if ((dev->vendor == PCI_VENDOR_ID_ATI) &&
|
||||
(dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) &&
|
||||
(dev->revision >= 0x40))
|
||||
if ((dev->vendor == PCI_VENDOR_ID_ATI &&
|
||||
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
|
||||
dev->revision >= 0x40) ||
|
||||
dev->vendor == PCI_VENDOR_ID_AMD)
|
||||
/* base address location etc changed in SB800 */
|
||||
retval = piix4_setup_sb800(dev, id);
|
||||
else
|
||||
|
@ -586,7 +586,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
||||
alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
|
||||
|
||||
/* 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,
|
||||
"I/O region 0x%08x for I2C already in use.\n",
|
||||
alg_data->base);
|
||||
@ -650,7 +651,7 @@ out_clock:
|
||||
out_unmap:
|
||||
iounmap((void *)alg_data->ioaddr);
|
||||
out_release:
|
||||
release_region(alg_data->base, I2C_PNX_REGION_SIZE);
|
||||
release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
|
||||
out_drvdata:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
out:
|
||||
@ -667,7 +668,7 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
|
||||
i2c_del_adapter(adap);
|
||||
i2c_pnx->set_clock_stop(pdev);
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
430
drivers/i2c/busses/i2c-scmi.c
Normal file
430
drivers/i2c/busses/i2c-scmi.c
Normal file
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* 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 @@
|
||||
|
||||
#define TAOS_STATE_INIT 0
|
||||
#define TAOS_STATE_IDLE 1
|
||||
#define TAOS_STATE_SEND 2
|
||||
#define TAOS_STATE_EOFF 2
|
||||
#define TAOS_STATE_RECV 3
|
||||
|
||||
#define TAOS_CMD_RESET 0x12
|
||||
#define TAOS_CMD_ECHO_ON '+'
|
||||
#define TAOS_CMD_ECHO_OFF '-'
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(wq);
|
||||
|
||||
@ -102,17 +104,9 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
|
||||
/* 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;
|
||||
}
|
||||
for (p = taos->buffer; *p; p++)
|
||||
serio_write(serio, *p);
|
||||
|
||||
taos->addr = addr;
|
||||
|
||||
/* Start the transaction and read the answer */
|
||||
@ -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,
|
||||
msecs_to_jiffies(150));
|
||||
if (taos->state != TAOS_STATE_IDLE
|
||||
|| taos->pos != 6) {
|
||||
|| taos->pos != 5) {
|
||||
dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
|
||||
taos->pos);
|
||||
return -EIO;
|
||||
@ -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);
|
||||
|
||||
/* Interpret the returned string */
|
||||
p = taos->buffer + 2;
|
||||
p = taos->buffer + 1;
|
||||
p[3] = '\0';
|
||||
if (!strcmp(p, "NAK"))
|
||||
return -ENODEV;
|
||||
@ -173,13 +167,9 @@ static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
|
||||
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);
|
||||
}
|
||||
case TAOS_STATE_EOFF:
|
||||
taos->state = TAOS_STATE_IDLE;
|
||||
wake_up_interruptible(&wq);
|
||||
break;
|
||||
case TAOS_STATE_RECV:
|
||||
taos->buffer[taos->pos++] = data;
|
||||
@ -257,6 +247,19 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
|
||||
}
|
||||
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);
|
||||
if (err)
|
||||
goto exit_close;
|
||||
|
@ -217,8 +217,10 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
|
||||
return;
|
||||
|
||||
error:
|
||||
dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
|
||||
scx200_acb_state_name[iface->state]);
|
||||
dev_err(&iface->adapter.dev,
|
||||
"%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->result = -EIO;
|
||||
|
@ -16,54 +16,6 @@ config DS1682
|
||||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "Taos TSL2550 ambient light sensor"
|
||||
depends on EXPERIMENTAL
|
||||
|
@ -11,9 +11,6 @@
|
||||
#
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
||||
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
|
@ -1,215 +0,0 @@
|
||||
/*
|
||||
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);
|
@ -1,198 +0,0 @@
|
||||
/*
|
||||
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 @@
|
||||
#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.2"
|
||||
#define DRIVER_VERSION "1.2"
|
||||
|
||||
/*
|
||||
* Defines
|
||||
@ -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)
|
||||
{
|
||||
unsigned long end;
|
||||
int loop = 0, ret = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
ret = i2c_smbus_read_byte_data(client, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!(ret & 0x80))
|
||||
return -EIO;
|
||||
return -EAGAIN;
|
||||
return ret & 0x7f; /* remove the "valid" bit */
|
||||
}
|
||||
|
||||
@ -285,8 +265,6 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
|
||||
return ret;
|
||||
ch0 = ret;
|
||||
|
||||
mdelay(1);
|
||||
|
||||
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -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
|
||||
* 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)
|
||||
return err;
|
||||
mdelay(1);
|
||||
if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
|
||||
if (err != TSL2550_POWER_UP)
|
||||
return -ENODEV;
|
||||
data->power_state = 1;
|
||||
|
||||
@ -374,7 +351,8 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
|
||||
struct tsl2550_data *data;
|
||||
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;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ static DEFINE_MUTEX(core_lock);
|
||||
static DEFINE_IDR(i2c_adapter_idr);
|
||||
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_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,
|
||||
|
||||
static int i2c_device_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_driver *driver = to_i2c_driver(drv);
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(drv);
|
||||
/* match on an id table if there is one */
|
||||
if (driver->id_table)
|
||||
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)
|
||||
|
||||
static int i2c_device_probe(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_driver *driver = to_i2c_driver(dev->driver);
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
int status;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (!driver->probe || !driver->id_table)
|
||||
return -ENODEV;
|
||||
client->driver = driver;
|
||||
@ -114,11 +123,11 @@ static int i2c_device_probe(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;
|
||||
int status;
|
||||
|
||||
if (!dev->driver)
|
||||
if (!client || !dev->driver)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
@ -136,37 +145,40 @@ static int i2c_device_remove(struct device *dev)
|
||||
|
||||
static void i2c_device_shutdown(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (!dev->driver)
|
||||
if (!client || !dev->driver)
|
||||
return;
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (driver->shutdown)
|
||||
driver->shutdown(to_i2c_client(dev));
|
||||
driver->shutdown(client);
|
||||
}
|
||||
|
||||
static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (!dev->driver)
|
||||
if (!client || !dev->driver)
|
||||
return 0;
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (!driver->suspend)
|
||||
return 0;
|
||||
return driver->suspend(to_i2c_client(dev), mesg);
|
||||
return driver->suspend(client, mesg);
|
||||
}
|
||||
|
||||
static int i2c_device_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (!dev->driver)
|
||||
if (!client || !dev->driver)
|
||||
return 0;
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (!driver->resume)
|
||||
return 0;
|
||||
return driver->resume(to_i2c_client(dev));
|
||||
return driver->resume(client);
|
||||
}
|
||||
|
||||
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
|
||||
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", client->name);
|
||||
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
|
||||
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -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);
|
||||
}
|
||||
|
||||
static struct device_attribute i2c_dev_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, show_client_name, NULL),
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_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) */
|
||||
__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 = {
|
||||
.name = "i2c",
|
||||
.dev_attrs = i2c_dev_attrs,
|
||||
.match = i2c_device_match,
|
||||
.uevent = i2c_device_uevent,
|
||||
.probe = i2c_device_probe,
|
||||
.remove = i2c_device_remove,
|
||||
.shutdown = i2c_device_shutdown,
|
||||
@ -208,6 +230,12 @@ struct bus_type 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
|
||||
@ -220,7 +248,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type);
|
||||
*/
|
||||
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)
|
||||
: NULL;
|
||||
}
|
||||
@ -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.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),
|
||||
client->addr);
|
||||
@ -368,13 +396,6 @@ static void i2c_adapter_dev_release(struct device *dev)
|
||||
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
|
||||
* 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,
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct device_attribute i2c_adapter_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, show_adapter_name, NULL),
|
||||
__ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device),
|
||||
__ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device),
|
||||
{ },
|
||||
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
|
||||
static 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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-adapter",
|
||||
.dev_attrs = i2c_adapter_attrs,
|
||||
static struct attribute_group i2c_adapter_attr_group = {
|
||||
.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)
|
||||
{
|
||||
struct i2c_devinfo *devinfo;
|
||||
@ -555,14 +591,22 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
adap->timeout = HZ;
|
||||
|
||||
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
|
||||
adap->dev.release = &i2c_adapter_dev_release;
|
||||
adap->dev.class = &i2c_adapter_class;
|
||||
adap->dev.bus = &i2c_bus_type;
|
||||
adap->dev.type = &i2c_adapter_type;
|
||||
res = device_register(&adap->dev);
|
||||
if (res)
|
||||
goto out_list;
|
||||
|
||||
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 */
|
||||
if (adap->nr < __i2c_first_dynamic_bus_num)
|
||||
i2c_scan_static_board_info(adap);
|
||||
@ -741,6 +785,11 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
||||
checking the returned value. */
|
||||
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 */
|
||||
init_completion(&adap->dev_released);
|
||||
device_unregister(&adap->dev);
|
||||
@ -768,9 +817,13 @@ EXPORT_SYMBOL(i2c_del_adapter);
|
||||
|
||||
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;
|
||||
|
||||
if (dev->type != &i2c_adapter_type)
|
||||
return 0;
|
||||
adapter = to_i2c_adapter(dev);
|
||||
|
||||
i2c_detect(adapter, driver);
|
||||
|
||||
/* Legacy drivers scan i2c busses directly */
|
||||
@ -809,8 +862,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
|
||||
INIT_LIST_HEAD(&driver->clients);
|
||||
/* Walk the adapters that are already present */
|
||||
mutex_lock(&core_lock);
|
||||
class_for_each_device(&i2c_adapter_class, NULL, driver,
|
||||
__attach_adapter);
|
||||
bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
|
||||
mutex_unlock(&core_lock);
|
||||
|
||||
return 0;
|
||||
@ -819,10 +871,14 @@ EXPORT_SYMBOL(i2c_register_driver);
|
||||
|
||||
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_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
|
||||
* probing (using a driver's detect method) */
|
||||
list_for_each_entry_safe(client, _n, &driver->clients, detected) {
|
||||
@ -850,8 +906,7 @@ static int __detach_adapter(struct device *dev, void *data)
|
||||
void i2c_del_driver(struct i2c_driver *driver)
|
||||
{
|
||||
mutex_lock(&core_lock);
|
||||
class_for_each_device(&i2c_adapter_class, NULL, driver,
|
||||
__detach_adapter);
|
||||
bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter);
|
||||
mutex_unlock(&core_lock);
|
||||
|
||||
driver_unregister(&driver->driver);
|
||||
@ -940,17 +995,23 @@ static int __init i2c_init(void)
|
||||
retval = bus_register(&i2c_bus_type);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = class_register(&i2c_adapter_class);
|
||||
if (retval)
|
||||
#ifdef CONFIG_I2C_COMPAT
|
||||
i2c_adapter_compat_class = class_compat_register("i2c-adapter");
|
||||
if (!i2c_adapter_compat_class) {
|
||||
retval = -ENOMEM;
|
||||
goto bus_err;
|
||||
}
|
||||
#endif
|
||||
retval = i2c_add_driver(&dummy_driver);
|
||||
if (retval)
|
||||
goto class_err;
|
||||
return 0;
|
||||
|
||||
class_err:
|
||||
class_unregister(&i2c_adapter_class);
|
||||
#ifdef CONFIG_I2C_COMPAT
|
||||
class_compat_unregister(i2c_adapter_compat_class);
|
||||
bus_err:
|
||||
#endif
|
||||
bus_unregister(&i2c_bus_type);
|
||||
return retval;
|
||||
}
|
||||
@ -958,7 +1019,9 @@ bus_err:
|
||||
static void __exit i2c_exit(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -27,17 +27,6 @@
|
||||
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. */
|
||||
|
||||
/*
|
||||
* ---- 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 ----------------------------------------------------
|
||||
*/
|
||||
|
@ -98,7 +98,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
|
||||
|
||||
/**
|
||||
* struct i2c_driver - represent an I2C device driver
|
||||
* @id: Unique driver ID (optional)
|
||||
* @class: What kind of i2c device we instantiate (for detect)
|
||||
* @attach_adapter: Callback for bus addition (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,
|
||||
* not allowed.
|
||||
*/
|
||||
struct i2c_driver {
|
||||
int id;
|
||||
unsigned int class;
|
||||
|
||||
/* Notifies the driver that a new bus has appeared or is about to be
|
||||
|
@ -543,6 +543,7 @@
|
||||
#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
|
||||
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
|
||||
#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_CS5536_ISA 0x2090
|
||||
#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
|
||||
|
Loading…
Reference in New Issue
Block a user