You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: i2c-viapro: Add support for SMBus Process Call transactions i2c: Restore i2c_smbus_process_call function i2c: Do earlier driver model init i2c: Only build Tyan SMBus mux drivers on x86 i2c: Guard against oopses from bad init sequences i2c: Document the implementation details of the /dev interface i2c: Improve dev-interface documentation i2c-parport-light: Don't register a platform device resource hwmon: (dme1737) Convert to a new-style i2c driver hwmon: (dme1737) Be less i2c-centric i2c/tps65010: Vibrator hookup to gpiolib i2c-viapro: Add VX800/VX820 support i2c: Renesas Highlander FPGA SMBus support i2c-pca-isa: Don't grab arbitrary resources i2c/isp1301_omap: Convert to a new-style i2c driver, part 2 i2c/isp1301_omap: Convert to a new-style i2c driver, part 1
This commit is contained in:
@@ -16,6 +16,9 @@ Supported adapters:
|
||||
* VIA Technologies, Inc. CX700
|
||||
Datasheet: available on request and under NDA from VIA
|
||||
|
||||
* VIA Technologies, Inc. VX800/VX820
|
||||
Datasheet: available on http://linux.via.com.tw
|
||||
|
||||
Authors:
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
||||
@@ -49,6 +52,7 @@ Your lspci -n listing must show one of these :
|
||||
device 1106:3372 (VT8237S)
|
||||
device 1106:3287 (VT8251)
|
||||
device 1106:8324 (CX700)
|
||||
device 1106:8353 (VX800/VX820)
|
||||
|
||||
If none of these show up, you should look in the BIOS for settings like
|
||||
enable ACPI / SMBus or even USB.
|
||||
@@ -57,5 +61,5 @@ Except for the oldest chips (VT82C596A/B, VT82C686A and most probably
|
||||
VT8231), this driver supports I2C block transactions. Such transactions
|
||||
are mainly useful to read from and write to EEPROMs.
|
||||
|
||||
The CX700 additionally appears to support SMBus PEC, although this driver
|
||||
doesn't implement it yet.
|
||||
The CX700/VX800/VX820 additionally appears to support SMBus PEC, although
|
||||
this driver doesn't implement it yet.
|
||||
|
||||
@@ -4,6 +4,10 @@ the /dev interface. You need to load module i2c-dev for this.
|
||||
|
||||
Each registered i2c adapter gets a number, counting from 0. You can
|
||||
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
|
||||
Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
|
||||
i2c adapters present on your system at a given time. i2cdetect is part of
|
||||
the i2c-tools package.
|
||||
|
||||
I2C device files are character device files with major device number 89
|
||||
and a minor device number corresponding to the number assigned as
|
||||
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
|
||||
@@ -17,30 +21,34 @@ So let's say you want to access an i2c adapter from a C program. The
|
||||
first thing to do is "#include <linux/i2c-dev.h>". Please note that
|
||||
there are two files named "i2c-dev.h" out there, one is distributed
|
||||
with the Linux kernel and is meant to be included from kernel
|
||||
driver code, the other one is distributed with lm_sensors and is
|
||||
driver code, the other one is distributed with i2c-tools and is
|
||||
meant to be included from user-space programs. You obviously want
|
||||
the second one here.
|
||||
|
||||
Now, you have to decide which adapter you want to access. You should
|
||||
inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
|
||||
somewhat dynamically, so you can not even assume /dev/i2c-0 is the
|
||||
first adapter.
|
||||
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
|
||||
Adapter numbers are assigned somewhat dynamically, so you can not
|
||||
assume much about them. They can even change from one boot to the next.
|
||||
|
||||
Next thing, open the device file, as follows:
|
||||
|
||||
int file;
|
||||
int adapter_nr = 2; /* probably dynamically determined */
|
||||
char filename[20];
|
||||
|
||||
sprintf(filename,"/dev/i2c-%d",adapter_nr);
|
||||
if ((file = open(filename,O_RDWR)) < 0) {
|
||||
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
|
||||
file = open(filename, O_RDWR);
|
||||
if (file < 0) {
|
||||
/* ERROR HANDLING; you can check errno to see what went wrong */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
When you have opened the device, you must specify with what device
|
||||
address you want to communicate:
|
||||
|
||||
int addr = 0x40; /* The I2C address */
|
||||
if (ioctl(file,I2C_SLAVE,addr) < 0) {
|
||||
|
||||
if (ioctl(file, I2C_SLAVE, addr) < 0) {
|
||||
/* ERROR HANDLING; you can check errno to see what went wrong */
|
||||
exit(1);
|
||||
}
|
||||
@@ -48,31 +56,41 @@ address you want to communicate:
|
||||
Well, you are all set up now. You can now use SMBus commands or plain
|
||||
I2C to communicate with your device. SMBus commands are preferred if
|
||||
the device supports them. Both are illustrated below.
|
||||
|
||||
__u8 register = 0x10; /* Device register to access */
|
||||
__s32 res;
|
||||
char buf[10];
|
||||
|
||||
/* Using SMBus commands */
|
||||
res = i2c_smbus_read_word_data(file,register);
|
||||
res = i2c_smbus_read_word_data(file, register);
|
||||
if (res < 0) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
} else {
|
||||
/* res contains the read word */
|
||||
}
|
||||
|
||||
/* Using I2C Write, equivalent of
|
||||
i2c_smbus_write_word_data(file,register,0x6543) */
|
||||
i2c_smbus_write_word_data(file, register, 0x6543) */
|
||||
buf[0] = register;
|
||||
buf[1] = 0x43;
|
||||
buf[2] = 0x65;
|
||||
if ( write(file,buf,3) != 3) {
|
||||
if (write(file, buf, 3) ! =3) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
}
|
||||
|
||||
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
|
||||
if (read(file,buf,1) != 1) {
|
||||
if (read(file, buf, 1) != 1) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
} else {
|
||||
/* buf[0] contains the read byte */
|
||||
}
|
||||
|
||||
Note that only a subset of the I2C and SMBus protocols can be achieved by
|
||||
the means of read() and write() calls. In particular, so-called combined
|
||||
transactions (mixing read and write messages in the same transaction)
|
||||
aren't supported. For this reason, this interface is almost never used by
|
||||
user-space programs.
|
||||
|
||||
IMPORTANT: because of the use of inline functions, you *have* to use
|
||||
'-O' or some variation when you compile your program!
|
||||
|
||||
@@ -80,31 +98,29 @@ IMPORTANT: because of the use of inline functions, you *have* to use
|
||||
Full interface description
|
||||
==========================
|
||||
|
||||
The following IOCTLs are defined and fully supported
|
||||
(see also i2c-dev.h):
|
||||
The following IOCTLs are defined:
|
||||
|
||||
ioctl(file,I2C_SLAVE,long addr)
|
||||
ioctl(file, I2C_SLAVE, long addr)
|
||||
Change slave address. The address is passed in the 7 lower bits of the
|
||||
argument (except for 10 bit addresses, passed in the 10 lower bits in this
|
||||
case).
|
||||
|
||||
ioctl(file,I2C_TENBIT,long select)
|
||||
ioctl(file, I2C_TENBIT, long select)
|
||||
Selects ten bit addresses if select not equals 0, selects normal 7 bit
|
||||
addresses if select equals 0. Default 0. This request is only valid
|
||||
if the adapter has I2C_FUNC_10BIT_ADDR.
|
||||
|
||||
ioctl(file,I2C_PEC,long select)
|
||||
ioctl(file, I2C_PEC, long select)
|
||||
Selects SMBus PEC (packet error checking) generation and verification
|
||||
if select not equals 0, disables if select equals 0. Default 0.
|
||||
Used only for SMBus transactions. This request only has an effect if the
|
||||
the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
|
||||
doesn't have any effect.
|
||||
|
||||
ioctl(file,I2C_FUNCS,unsigned long *funcs)
|
||||
ioctl(file, I2C_FUNCS, unsigned long *funcs)
|
||||
Gets the adapter functionality and puts it in *funcs.
|
||||
|
||||
ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
|
||||
|
||||
ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
|
||||
Do combined read/write transaction without stop in between.
|
||||
Only valid if the adapter has I2C_FUNC_I2C. The argument is
|
||||
a pointer to a
|
||||
@@ -120,10 +136,9 @@ ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
|
||||
The slave address and whether to use ten bit address mode has to be
|
||||
set in each message, overriding the values set with the above ioctl's.
|
||||
|
||||
|
||||
Other values are NOT supported at this moment, except for I2C_SMBUS,
|
||||
which you should never directly call; instead, use the access functions
|
||||
below.
|
||||
ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
|
||||
Not meant to be called directly; instead, use the access functions
|
||||
below.
|
||||
|
||||
You can do plain i2c transactions by using read(2) and write(2) calls.
|
||||
You do not need to pass the address byte; instead, set it through
|
||||
@@ -148,7 +163,52 @@ what happened. The 'write' transactions return 0 on success; the
|
||||
returns the number of values read. The block buffers need not be longer
|
||||
than 32 bytes.
|
||||
|
||||
The above functions are all macros, that resolve to calls to the
|
||||
i2c_smbus_access function, that on its turn calls a specific ioctl
|
||||
The above functions are all inline functions, that resolve to calls to
|
||||
the i2c_smbus_access function, that on its turn calls a specific ioctl
|
||||
with the data in a specific format. Read the source code if you
|
||||
want to know what happens behind the screens.
|
||||
|
||||
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
For the interested, here's the code flow which happens inside the kernel
|
||||
when you use the /dev interface to I2C:
|
||||
|
||||
1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
|
||||
section "C example" above.
|
||||
|
||||
2* These open() and ioctl() calls are handled by the i2c-dev kernel
|
||||
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
|
||||
respectively. You can think of i2c-dev as a generic I2C chip driver
|
||||
that can be programmed from user-space.
|
||||
|
||||
3* Some ioctl() calls are for administrative tasks and are handled by
|
||||
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
|
||||
device you want to access) and I2C_PEC (enable or disable SMBus error
|
||||
checking on future transactions.)
|
||||
|
||||
4* Other ioctl() calls are converted to in-kernel function calls by
|
||||
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
|
||||
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
|
||||
performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().
|
||||
|
||||
The i2c-dev driver is responsible for checking all the parameters that
|
||||
come from user-space for validity. After this point, there is no
|
||||
difference between these calls that came from user-space through i2c-dev
|
||||
and calls that would have been performed by kernel I2C chip drivers
|
||||
directly. This means that I2C bus drivers don't need to implement
|
||||
anything special to support access from user-space.
|
||||
|
||||
5* These i2c-core.c/i2c.h functions are wrappers to the actual
|
||||
implementation of your I2C bus driver. Each adapter must declare
|
||||
callback functions implementing these standard calls.
|
||||
i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
|
||||
while i2c-core.c:i2c_smbus_xfer() calls either
|
||||
adapter.algo->smbus_xfer() if it is implemented, or if not,
|
||||
i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
|
||||
i2c_adapter.algo->master_xfer().
|
||||
|
||||
After your I2C bus driver has processed these requests, execution runs
|
||||
up the call chain, with almost no processing done, except by i2c-dev to
|
||||
package the returned data, if any, in suitable format for the ioctl.
|
||||
|
||||
@@ -109,8 +109,8 @@ specified through the Comm byte.
|
||||
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
|
||||
|
||||
|
||||
SMBus Process Call
|
||||
==================
|
||||
SMBus Process Call: i2c_smbus_process_call()
|
||||
=============================================
|
||||
|
||||
This command selects a device register (through the Comm byte), sends
|
||||
16 bits of data to it, and reads 16 bits of data in return.
|
||||
|
||||
@@ -606,6 +606,8 @@ SMBus communication
|
||||
extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
|
||||
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
|
||||
u8 command, u16 value);
|
||||
extern s32 i2c_smbus_process_call(struct i2c_client *client,
|
||||
u8 command, u16 value);
|
||||
extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
|
||||
u8 command, u8 *values);
|
||||
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
|
||||
@@ -621,8 +623,6 @@ These ones were removed from i2c-core because they had no users, but could
|
||||
be added back later if needed:
|
||||
|
||||
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
|
||||
extern s32 i2c_smbus_process_call(struct i2c_client * client,
|
||||
u8 command, u16 value);
|
||||
extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
|
||||
u8 command, u8 length,
|
||||
u8 *values)
|
||||
|
||||
@@ -476,6 +476,10 @@ static struct i2c_board_info __initdata h3_i2c_board_info[] = {
|
||||
I2C_BOARD_INFO("tps65013", 0x48),
|
||||
/* .irq = OMAP_GPIO_IRQ(??), */
|
||||
},
|
||||
{
|
||||
I2C_BOARD_INFO("isp1301_omap", 0x2d),
|
||||
.irq = OMAP_GPIO_IRQ(14),
|
||||
},
|
||||
};
|
||||
|
||||
static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -391,6 +392,13 @@ static struct omap_board_config_kernel h4_config[] = {
|
||||
{ OMAP_TAG_LCD, &h4_lcd_config },
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata h4_i2c_board_info[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("isp1301_omap", 0x2d),
|
||||
.irq = OMAP_GPIO_IRQ(125),
|
||||
},
|
||||
};
|
||||
|
||||
static void __init omap_h4_init(void)
|
||||
{
|
||||
/*
|
||||
@@ -411,6 +419,9 @@ static void __init omap_h4_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
i2c_register_board_info(1, h4_i2c_board_info,
|
||||
ARRAY_SIZE(h4_i2c_board_info));
|
||||
|
||||
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
|
||||
omap_board_config = h4_config;
|
||||
omap_board_config_size = ARRAY_SIZE(h4_config);
|
||||
|
||||
+153
-167
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ config I2C_AMD756
|
||||
|
||||
config I2C_AMD756_S4882
|
||||
tristate "SMBus multiplexing on the Tyan S4882"
|
||||
depends on I2C_AMD756 && EXPERIMENTAL
|
||||
depends on I2C_AMD756 && X86 && EXPERIMENTAL
|
||||
help
|
||||
Enabling this option will add specific SMBus support for the Tyan
|
||||
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
||||
@@ -148,7 +148,7 @@ config I2C_NFORCE2
|
||||
|
||||
config I2C_NFORCE2_S4985
|
||||
tristate "SMBus multiplexing on the Tyan S4985"
|
||||
depends on I2C_NFORCE2 && EXPERIMENTAL
|
||||
depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
|
||||
help
|
||||
Enabling this option will add specific SMBus support for the Tyan
|
||||
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
||||
@@ -209,7 +209,7 @@ config I2C_VIA
|
||||
will be called i2c-via.
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA VT82C596/82C686/82xx and CX700"
|
||||
tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
|
||||
depends on PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
@@ -223,6 +223,8 @@ config I2C_VIAPRO
|
||||
VT8237R/A/S
|
||||
VT8251
|
||||
CX700
|
||||
VX800
|
||||
VX820
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-viapro.
|
||||
@@ -330,6 +332,18 @@ config I2C_GPIO
|
||||
This is a very simple bitbanging I2C driver utilizing the
|
||||
arch-neutral GPIO API to control the SCL and SDA lines.
|
||||
|
||||
config I2C_HIGHLANDER
|
||||
tristate "Highlander FPGA SMBus interface"
|
||||
depends on SH_HIGHLANDER
|
||||
help
|
||||
If you say yes to this option, support will be included for
|
||||
the SMBus interface located in the FPGA on various Highlander
|
||||
boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
|
||||
FPGAs. This is wholly unrelated to the SoC I2C.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-highlander.
|
||||
|
||||
config I2C_IBM_IIC
|
||||
tristate "IBM PPC 4xx on-chip I2C interface"
|
||||
depends on 4xx
|
||||
|
||||
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
|
||||
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
|
||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
|
||||
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Renesas Solutions Highlander FPGA I2C/SMBus support.
|
||||
*
|
||||
* Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
|
||||
*
|
||||
* Copyright (C) 2008 Paul Mundt
|
||||
* Copyright (C) 2008 Renesas Solutions Corp.
|
||||
* Copyright (C) 2008 Atom Create Engineering Co., Ltd.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file "COPYING" in the main directory
|
||||
* of this archive for more details.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define SMCR 0x00
|
||||
#define SMCR_START (1 << 0)
|
||||
#define SMCR_IRIC (1 << 1)
|
||||
#define SMCR_BBSY (1 << 2)
|
||||
#define SMCR_ACKE (1 << 3)
|
||||
#define SMCR_RST (1 << 4)
|
||||
#define SMCR_IEIC (1 << 6)
|
||||
|
||||
#define SMSMADR 0x02
|
||||
|
||||
#define SMMR 0x04
|
||||
#define SMMR_MODE0 (1 << 0)
|
||||
#define SMMR_MODE1 (1 << 1)
|
||||
#define SMMR_CAP (1 << 3)
|
||||
#define SMMR_TMMD (1 << 4)
|
||||
#define SMMR_SP (1 << 7)
|
||||
|
||||
#define SMSADR 0x06
|
||||
#define SMTRDR 0x46
|
||||
|
||||
struct highlander_i2c_dev {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct i2c_adapter adapter;
|
||||
struct completion cmd_complete;
|
||||
unsigned long last_read_time;
|
||||
int irq;
|
||||
u8 *buf;
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
static int iic_force_poll, iic_force_normal;
|
||||
static int iic_timeout = 1000, iic_read_delay;
|
||||
|
||||
static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
|
||||
}
|
||||
|
||||
static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
|
||||
}
|
||||
|
||||
static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
|
||||
}
|
||||
|
||||
static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
|
||||
}
|
||||
|
||||
static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
u16 smmr;
|
||||
|
||||
smmr = ioread16(dev->base + SMMR);
|
||||
smmr |= SMMR_TMMD;
|
||||
|
||||
if (iic_force_normal)
|
||||
smmr &= ~SMMR_SP;
|
||||
else
|
||||
smmr |= SMMR_SP;
|
||||
|
||||
iowrite16(smmr, dev->base + SMMR);
|
||||
}
|
||||
|
||||
static void smbus_write_data(u8 *src, u16 *dst, int len)
|
||||
{
|
||||
for (; len > 1; len -= 2) {
|
||||
*dst++ = be16_to_cpup((u16 *)src);
|
||||
src += 2;
|
||||
}
|
||||
|
||||
if (len)
|
||||
*dst = *src << 8;
|
||||
}
|
||||
|
||||
static void smbus_read_data(u16 *src, u8 *dst, int len)
|
||||
{
|
||||
for (; len > 1; len -= 2) {
|
||||
*(u16 *)dst = cpu_to_be16p(src++);
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if (len)
|
||||
*dst = *src >> 8;
|
||||
}
|
||||
|
||||
static void highlander_i2c_command(struct highlander_i2c_dev *dev,
|
||||
u8 command, int len)
|
||||
{
|
||||
unsigned int i;
|
||||
u16 cmd = (command << 8) | command;
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
if (len - i == 1)
|
||||
cmd = command << 8;
|
||||
iowrite16(cmd, dev->base + SMSADR + i);
|
||||
dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(iic_timeout);
|
||||
while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
|
||||
return highlander_i2c_wait_for_bbsy(dev);
|
||||
}
|
||||
|
||||
static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
u16 tmp = ioread16(dev->base + SMCR);
|
||||
|
||||
if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
|
||||
dev_warn(dev->dev, "ack abnormality\n");
|
||||
return highlander_i2c_reset(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct highlander_i2c_dev *dev = dev_id;
|
||||
|
||||
highlander_i2c_done(dev);
|
||||
complete(&dev->cmd_complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u16 smcr;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(iic_timeout);
|
||||
for (;;) {
|
||||
smcr = ioread16(dev->base + SMCR);
|
||||
|
||||
/*
|
||||
* Don't bother checking ACKE here, this and the reset
|
||||
* are handled in highlander_i2c_wait_xfer_done() when
|
||||
* waiting for the ACK.
|
||||
*/
|
||||
|
||||
if (smcr & SMCR_IRIC)
|
||||
return;
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
|
||||
cpu_relax();
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
dev_err(dev->dev, "polling timed out\n");
|
||||
}
|
||||
|
||||
static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
if (dev->irq)
|
||||
wait_for_completion_timeout(&dev->cmd_complete,
|
||||
msecs_to_jiffies(iic_timeout));
|
||||
else
|
||||
/* busy looping, the IRQ of champions */
|
||||
highlander_i2c_poll(dev);
|
||||
|
||||
return highlander_i2c_wait_for_ack(dev);
|
||||
}
|
||||
|
||||
static int highlander_i2c_read(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
int i, cnt;
|
||||
u16 data[16];
|
||||
|
||||
if (highlander_i2c_wait_for_bbsy(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
highlander_i2c_start(dev);
|
||||
|
||||
if (highlander_i2c_wait_xfer_done(dev)) {
|
||||
dev_err(dev->dev, "Arbitration loss\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* The R0P7780LC0011RL FPGA needs a significant delay between
|
||||
* data read cycles, otherwise the transciever gets confused and
|
||||
* garbage is returned when the read is subsequently aborted.
|
||||
*
|
||||
* It is not sufficient to wait for BBSY.
|
||||
*
|
||||
* While this generally only applies to the older SH7780-based
|
||||
* Highlanders, the same issue can be observed on SH7785 ones,
|
||||
* albeit less frequently. SH7780-based Highlanders may need
|
||||
* this to be as high as 1000 ms.
|
||||
*/
|
||||
if (iic_read_delay && time_before(jiffies, dev->last_read_time +
|
||||
msecs_to_jiffies(iic_read_delay)))
|
||||
msleep(jiffies_to_msecs((dev->last_read_time +
|
||||
msecs_to_jiffies(iic_read_delay)) - jiffies));
|
||||
|
||||
cnt = (dev->buf_len + 1) >> 1;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
|
||||
dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
|
||||
}
|
||||
|
||||
smbus_read_data(data, dev->buf, dev->buf_len);
|
||||
|
||||
dev->last_read_time = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int highlander_i2c_write(struct highlander_i2c_dev *dev)
|
||||
{
|
||||
int i, cnt;
|
||||
u16 data[16];
|
||||
|
||||
smbus_write_data(dev->buf, data, dev->buf_len);
|
||||
|
||||
cnt = (dev->buf_len + 1) >> 1;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
|
||||
dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
|
||||
}
|
||||
|
||||
if (highlander_i2c_wait_for_bbsy(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
highlander_i2c_start(dev);
|
||||
|
||||
return highlander_i2c_wait_xfer_done(dev);
|
||||
}
|
||||
|
||||
static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size,
|
||||
union i2c_smbus_data *data)
|
||||
{
|
||||
struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int read = read_write & I2C_SMBUS_READ;
|
||||
u16 tmp;
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
|
||||
dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
|
||||
addr, command, read_write, size);
|
||||
|
||||
/*
|
||||
* Set up the buffer and transfer size
|
||||
*/
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
dev->buf = &data->byte;
|
||||
dev->buf_len = 1;
|
||||
break;
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
dev->buf = &data->block[1];
|
||||
dev->buf_len = data->block[0];
|
||||
break;
|
||||
default:
|
||||
dev_err(dev->dev, "unsupported command %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the mode setting
|
||||
*/
|
||||
tmp = ioread16(dev->base + SMMR);
|
||||
tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
|
||||
|
||||
switch (dev->buf_len) {
|
||||
case 1:
|
||||
/* default */
|
||||
break;
|
||||
case 8:
|
||||
tmp |= SMMR_MODE0;
|
||||
break;
|
||||
case 16:
|
||||
tmp |= SMMR_MODE1;
|
||||
break;
|
||||
case 32:
|
||||
tmp |= (SMMR_MODE0 | SMMR_MODE1);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iowrite16(tmp, dev->base + SMMR);
|
||||
|
||||
/* Ensure we're in a sane state */
|
||||
highlander_i2c_done(dev);
|
||||
|
||||
/* Set slave address */
|
||||
iowrite16((addr << 1) | read, dev->base + SMSMADR);
|
||||
|
||||
highlander_i2c_command(dev, command, dev->buf_len);
|
||||
|
||||
if (read)
|
||||
return highlander_i2c_read(dev);
|
||||
else
|
||||
return highlander_i2c_write(dev);
|
||||
}
|
||||
|
||||
static u32 highlander_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm highlander_i2c_algo = {
|
||||
.smbus_xfer = highlander_i2c_smbus_xfer,
|
||||
.functionality = highlander_i2c_func,
|
||||
};
|
||||
|
||||
static int __devinit highlander_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct highlander_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (unlikely(!res)) {
|
||||
dev_err(&pdev->dev, "no mem resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
|
||||
if (unlikely(!dev))
|
||||
return -ENOMEM;
|
||||
|
||||
dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
|
||||
if (unlikely(!dev->base)) {
|
||||
ret = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
if (iic_force_poll)
|
||||
dev->irq = 0;
|
||||
|
||||
if (dev->irq) {
|
||||
ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
|
||||
pdev->name, dev);
|
||||
if (unlikely(ret))
|
||||
goto err_unmap;
|
||||
|
||||
highlander_i2c_irq_enable(dev);
|
||||
} else {
|
||||
dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
|
||||
highlander_i2c_irq_disable(dev);
|
||||
}
|
||||
|
||||
dev->last_read_time = jiffies; /* initial read jiffies */
|
||||
|
||||
highlander_i2c_setup(dev);
|
||||
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &highlander_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->nr = pdev->id;
|
||||
|
||||
/*
|
||||
* Reset the adapter
|
||||
*/
|
||||
ret = highlander_i2c_reset(dev);
|
||||
if (unlikely(ret)) {
|
||||
dev_err(&pdev->dev, "controller didn't come up\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (unlikely(ret)) {
|
||||
dev_err(&pdev->dev, "failure adding adapter\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
if (dev->irq)
|
||||
free_irq(dev->irq, dev);
|
||||
err_unmap:
|
||||
iounmap(dev->base);
|
||||
err:
|
||||
kfree(dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit highlander_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
|
||||
if (dev->irq)
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
iounmap(dev->base);
|
||||
kfree(dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver highlander_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-highlander",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = highlander_i2c_probe,
|
||||
.remove = __devexit_p(highlander_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init highlander_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&highlander_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit highlander_i2c_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&highlander_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(highlander_i2c_init);
|
||||
module_exit(highlander_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Paul Mundt");
|
||||
MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
module_param(iic_force_poll, bool, 0);
|
||||
module_param(iic_force_normal, bool, 0);
|
||||
module_param(iic_timeout, int, 0);
|
||||
module_param(iic_read_delay, int, 0);
|
||||
|
||||
MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
|
||||
MODULE_PARM_DESC(iic_force_normal,
|
||||
"Force normal mode (100 kHz), default is fast mode (400 kHz)");
|
||||
MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
|
||||
MODULE_PARM_DESC(iic_read_delay,
|
||||
"Delay between data read cycles (default 0 ms)");
|
||||
@@ -123,11 +123,6 @@ static struct i2c_adapter parport_adapter = {
|
||||
static int __devinit i2c_parport_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
/* Reset hardware to a sane state (SCL and SDA high) */
|
||||
parport_setsda(NULL, 1);
|
||||
@@ -138,29 +133,19 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
|
||||
|
||||
parport_adapter.dev.parent = &pdev->dev;
|
||||
err = i2c_bit_add_bus(&parport_adapter);
|
||||
if (err) {
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "Unable to register with I2C\n");
|
||||
goto exit_region;
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_region:
|
||||
release_region(res->start, res->end - res->start + 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit i2c_parport_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
i2c_del_adapter(&parport_adapter);
|
||||
|
||||
/* Un-init if needed (power off...) */
|
||||
if (adapter_parm[type].init.val)
|
||||
line_set(0, &adapter_parm[type].init);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(res->start, res->end - res->start + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -175,12 +160,6 @@ static struct platform_driver i2c_parport_driver = {
|
||||
|
||||
static int __init i2c_parport_device_add(u16 address)
|
||||
{
|
||||
struct resource res = {
|
||||
.start = address,
|
||||
.end = address + 2,
|
||||
.name = DRVNAME,
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
int err;
|
||||
|
||||
pdev = platform_device_alloc(DRVNAME, -1);
|
||||
@@ -190,13 +169,6 @@ static int __init i2c_parport_device_add(u16 address)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = platform_device_add_resources(pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed "
|
||||
"(%d)\n", err);
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
|
||||
@@ -231,13 +203,16 @@ static int __init i2c_parport_init(void)
|
||||
base = DEFAULT_BASE;
|
||||
}
|
||||
|
||||
if (!request_region(base, 3, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
if (!adapter_parm[type].getscl.val)
|
||||
parport_algo_data.getscl = NULL;
|
||||
|
||||
/* Sets global pdev as a side effect */
|
||||
err = i2c_parport_device_add(base);
|
||||
if (err)
|
||||
goto exit;
|
||||
goto exit_release;
|
||||
|
||||
err = platform_driver_register(&i2c_parport_driver);
|
||||
if (err)
|
||||
@@ -247,7 +222,8 @@ static int __init i2c_parport_init(void)
|
||||
|
||||
exit_device:
|
||||
platform_device_unregister(pdev);
|
||||
exit:
|
||||
exit_release:
|
||||
release_region(base, 3);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -255,6 +231,7 @@ static void __exit i2c_parport_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&i2c_parport_driver);
|
||||
platform_device_unregister(pdev);
|
||||
release_region(base, 3);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
#define DRIVER "i2c-pca-isa"
|
||||
#define IO_SIZE 4
|
||||
|
||||
static unsigned long base = 0x330;
|
||||
static int irq = 10;
|
||||
static unsigned long base;
|
||||
static int irq = -1;
|
||||
|
||||
/* Data sheet recommends 59kHz for 100kHz operation due to variation
|
||||
* in the actual clock rate */
|
||||
@@ -107,6 +107,19 @@ static struct i2c_adapter pca_isa_ops = {
|
||||
.timeout = 100,
|
||||
};
|
||||
|
||||
static int __devinit pca_isa_match(struct device *dev, unsigned int id)
|
||||
{
|
||||
int match = base != 0;
|
||||
|
||||
if (match) {
|
||||
if (irq <= -1)
|
||||
dev_warn(dev, "Using polling mode (specify irq)\n");
|
||||
} else
|
||||
dev_err(dev, "Please specify I/O base\n");
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
init_waitqueue_head(&pca_wait);
|
||||
@@ -153,7 +166,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
|
||||
{
|
||||
i2c_del_adapter(&pca_isa_ops);
|
||||
|
||||
if (irq > 0) {
|
||||
if (irq > -1) {
|
||||
disable_irq(irq);
|
||||
free_irq(irq, &pca_isa_ops);
|
||||
}
|
||||
@@ -163,6 +176,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
|
||||
}
|
||||
|
||||
static struct isa_driver pca_isa_driver = {
|
||||
.match = pca_isa_match,
|
||||
.probe = pca_isa_probe,
|
||||
.remove = __devexit_p(pca_isa_remove),
|
||||
.driver = {
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
VT8237S 0x3372 yes
|
||||
VT8251 0x3287 yes
|
||||
CX700 0x8324 yes
|
||||
VX800/VX820 0x8353 yes
|
||||
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
@@ -82,6 +83,7 @@ static unsigned short SMBHSTCFG = 0xD2;
|
||||
#define VT596_BYTE 0x04
|
||||
#define VT596_BYTE_DATA 0x08
|
||||
#define VT596_WORD_DATA 0x0C
|
||||
#define VT596_PROC_CALL 0x10
|
||||
#define VT596_BLOCK_DATA 0x14
|
||||
#define VT596_I2C_BLOCK_DATA 0x34
|
||||
|
||||
@@ -232,6 +234,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||
}
|
||||
size = VT596_WORD_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
outb_p(command, SMBHSTCMD);
|
||||
outb_p(data->word & 0xff, SMBHSTDAT0);
|
||||
outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
|
||||
size = VT596_PROC_CALL;
|
||||
break;
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
if (!(vt596_features & FEATURE_I2CBLOCK))
|
||||
goto exit_unsupported;
|
||||
@@ -262,6 +270,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (size == VT596_PROC_CALL)
|
||||
read_write = I2C_SMBUS_READ;
|
||||
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
|
||||
return 0;
|
||||
|
||||
@@ -271,6 +282,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||
data->byte = inb_p(SMBHSTDAT0);
|
||||
break;
|
||||
case VT596_WORD_DATA:
|
||||
case VT596_PROC_CALL:
|
||||
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
|
||||
break;
|
||||
case VT596_I2C_BLOCK_DATA:
|
||||
@@ -295,7 +307,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
|
||||
if (vt596_features & FEATURE_I2CBLOCK)
|
||||
func |= I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
@@ -396,6 +408,7 @@ found:
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_VIA_CX700:
|
||||
case PCI_DEVICE_ID_VIA_VX800:
|
||||
case PCI_DEVICE_ID_VIA_8251:
|
||||
case PCI_DEVICE_ID_VIA_8237:
|
||||
case PCI_DEVICE_ID_VIA_8237A:
|
||||
@@ -459,6 +472,8 @@ static struct pci_device_id vt596_ids[] = {
|
||||
.driver_data = SMBBA3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
|
||||
.driver_data = SMBBA3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
|
||||
.driver_data = SMBBA3 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
||||
@@ -49,10 +49,9 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
struct isp1301 {
|
||||
struct otg_transceiver otg;
|
||||
struct i2c_client client;
|
||||
struct i2c_client *client;
|
||||
void (*i2c_release)(struct device *dev);
|
||||
|
||||
int irq;
|
||||
int irq_type;
|
||||
|
||||
u32 last_otg_ctrl;
|
||||
@@ -138,14 +137,6 @@ static inline void notresponding(struct isp1301 *isp)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* only two addresses possible */
|
||||
#define ISP_BASE 0x2c
|
||||
static unsigned short normal_i2c[] = {
|
||||
ISP_BASE, ISP_BASE + 1,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_driver isp1301_driver;
|
||||
|
||||
/* smbus apis are used for portability */
|
||||
@@ -153,25 +144,25 @@ static struct i2c_driver isp1301_driver;
|
||||
static inline u8
|
||||
isp1301_get_u8(struct isp1301 *isp, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(&isp->client, reg + 0);
|
||||
return i2c_smbus_read_byte_data(isp->client, reg + 0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isp1301_get_u16(struct isp1301 *isp, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_word_data(&isp->client, reg);
|
||||
return i2c_smbus_read_word_data(isp->client, reg);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
|
||||
return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
|
||||
return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@@ -349,10 +340,10 @@ isp1301_defer_work(struct isp1301 *isp, int work)
|
||||
int status;
|
||||
|
||||
if (isp && !test_and_set_bit(work, &isp->todo)) {
|
||||
(void) get_device(&isp->client.dev);
|
||||
(void) get_device(&isp->client->dev);
|
||||
status = schedule_work(&isp->work);
|
||||
if (!status && !isp->working)
|
||||
dev_vdbg(&isp->client.dev,
|
||||
dev_vdbg(&isp->client->dev,
|
||||
"work item %d may be lost\n", work);
|
||||
}
|
||||
}
|
||||
@@ -1135,7 +1126,7 @@ isp1301_work(struct work_struct *work)
|
||||
/* transfer state from otg engine to isp1301 */
|
||||
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
|
||||
otg_update_isp(isp);
|
||||
put_device(&isp->client.dev);
|
||||
put_device(&isp->client->dev);
|
||||
}
|
||||
#endif
|
||||
/* transfer state from isp1301 to otg engine */
|
||||
@@ -1143,7 +1134,7 @@ isp1301_work(struct work_struct *work)
|
||||
u8 stat = isp1301_clear_latch(isp);
|
||||
|
||||
isp_update_otg(isp, stat);
|
||||
put_device(&isp->client.dev);
|
||||
put_device(&isp->client->dev);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
|
||||
@@ -1178,7 +1169,7 @@ isp1301_work(struct work_struct *work)
|
||||
}
|
||||
host_resume(isp);
|
||||
// mdelay(10);
|
||||
put_device(&isp->client.dev);
|
||||
put_device(&isp->client->dev);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
|
||||
@@ -1187,15 +1178,15 @@ isp1301_work(struct work_struct *work)
|
||||
if (!stop)
|
||||
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
|
||||
#endif
|
||||
put_device(&isp->client.dev);
|
||||
put_device(&isp->client->dev);
|
||||
}
|
||||
|
||||
if (isp->todo)
|
||||
dev_vdbg(&isp->client.dev,
|
||||
dev_vdbg(&isp->client->dev,
|
||||
"work done, todo = 0x%lx\n",
|
||||
isp->todo);
|
||||
if (stop) {
|
||||
dev_dbg(&isp->client.dev, "stop\n");
|
||||
dev_dbg(&isp->client->dev, "stop\n");
|
||||
break;
|
||||
}
|
||||
} while (isp->todo);
|
||||
@@ -1219,7 +1210,7 @@ static void isp1301_release(struct device *dev)
|
||||
{
|
||||
struct isp1301 *isp;
|
||||
|
||||
isp = container_of(dev, struct isp1301, client.dev);
|
||||
isp = dev_get_drvdata(dev);
|
||||
|
||||
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
|
||||
if (isp->i2c_release)
|
||||
@@ -1229,15 +1220,15 @@ static void isp1301_release(struct device *dev)
|
||||
|
||||
static struct isp1301 *the_transceiver;
|
||||
|
||||
static int isp1301_detach_client(struct i2c_client *i2c)
|
||||
static int __exit isp1301_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct isp1301 *isp;
|
||||
|
||||
isp = container_of(i2c, struct isp1301, client);
|
||||
isp = i2c_get_clientdata(i2c);
|
||||
|
||||
isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
|
||||
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
|
||||
free_irq(isp->irq, isp);
|
||||
free_irq(i2c->irq, isp);
|
||||
#ifdef CONFIG_USB_OTG
|
||||
otg_unbind(isp);
|
||||
#endif
|
||||
@@ -1252,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
|
||||
put_device(&i2c->dev);
|
||||
the_transceiver = 0;
|
||||
|
||||
return i2c_detach_client(i2c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@@ -1285,7 +1276,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
|
||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||
INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
|
||||
|
||||
dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
|
||||
dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1310,7 +1301,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
isp->otg.host = host;
|
||||
dev_dbg(&isp->client.dev, "registered host\n");
|
||||
dev_dbg(&isp->client->dev, "registered host\n");
|
||||
host_suspend(isp);
|
||||
if (isp->otg.gadget)
|
||||
return isp1301_otg_enable(isp);
|
||||
@@ -1325,7 +1316,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
||||
if (machine_is_omap_h2())
|
||||
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
|
||||
|
||||
dev_info(&isp->client.dev, "A-Host sessions ok\n");
|
||||
dev_info(&isp->client->dev, "A-Host sessions ok\n");
|
||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
|
||||
INTR_ID_GND);
|
||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||
@@ -1343,7 +1334,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
||||
return 0;
|
||||
|
||||
#else
|
||||
dev_dbg(&isp->client.dev, "host sessions not allowed\n");
|
||||
dev_dbg(&isp->client->dev, "host sessions not allowed\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
@@ -1370,7 +1361,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
isp->otg.gadget = gadget;
|
||||
dev_dbg(&isp->client.dev, "registered gadget\n");
|
||||
dev_dbg(&isp->client->dev, "registered gadget\n");
|
||||
/* gadget driver may be suspended until vbus_connect () */
|
||||
if (isp->otg.host)
|
||||
return isp1301_otg_enable(isp);
|
||||
@@ -1395,7 +1386,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
||||
INTR_SESS_VLD);
|
||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||
INTR_VBUS_VLD);
|
||||
dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
|
||||
dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
|
||||
dump_regs(isp, __func__);
|
||||
|
||||
/* If this has a Mini-AB connector, this mode is highly
|
||||
@@ -1408,7 +1399,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
||||
return 0;
|
||||
|
||||
#else
|
||||
dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
|
||||
dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
@@ -1508,12 +1499,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* no error returns, they'd just make bus scanning stop */
|
||||
static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
|
||||
static int __init isp1301_probe(struct i2c_client *i2c)
|
||||
{
|
||||
int status;
|
||||
struct isp1301 *isp;
|
||||
struct i2c_client *i2c;
|
||||
|
||||
if (the_transceiver)
|
||||
return 0;
|
||||
@@ -1527,37 +1516,19 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
|
||||
isp->timer.function = isp1301_timer;
|
||||
isp->timer.data = (unsigned long) isp;
|
||||
|
||||
isp->irq = -1;
|
||||
isp->client.addr = address;
|
||||
i2c_set_clientdata(&isp->client, isp);
|
||||
isp->client.adapter = bus;
|
||||
isp->client.driver = &isp1301_driver;
|
||||
strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
|
||||
i2c = &isp->client;
|
||||
i2c_set_clientdata(i2c, isp);
|
||||
isp->client = i2c;
|
||||
|
||||
/* if this is a true probe, verify the chip ... */
|
||||
if (kind < 0) {
|
||||
status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
|
||||
if (status != I2C_VENDOR_ID_PHILIPS) {
|
||||
dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
|
||||
address, status);
|
||||
goto fail1;
|
||||
}
|
||||
status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
|
||||
if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
|
||||
dev_dbg(&bus->dev, "%d not isp1301, %d\n",
|
||||
address, status);
|
||||
goto fail1;
|
||||
}
|
||||
/* verify the chip (shouldn't be necesary) */
|
||||
status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
|
||||
if (status != I2C_VENDOR_ID_PHILIPS) {
|
||||
dev_dbg(&i2c->dev, "not philips id: %d\n", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = i2c_attach_client(i2c);
|
||||
if (status < 0) {
|
||||
dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
|
||||
DRIVER_NAME, address, status);
|
||||
fail1:
|
||||
kfree(isp);
|
||||
return 0;
|
||||
status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
|
||||
if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
|
||||
dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
|
||||
goto fail;
|
||||
}
|
||||
isp->i2c_release = i2c->dev.release;
|
||||
i2c->dev.release = isp1301_release;
|
||||
@@ -1586,7 +1557,7 @@ fail1:
|
||||
status = otg_bind(isp);
|
||||
if (status < 0) {
|
||||
dev_dbg(&i2c->dev, "can't bind OTG\n");
|
||||
goto fail2;
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1599,26 +1570,21 @@ fail1:
|
||||
|
||||
/* IRQ wired at M14 */
|
||||
omap_cfg_reg(M14_1510_GPIO2);
|
||||
isp->irq = OMAP_GPIO_IRQ(2);
|
||||
if (gpio_request(2, "isp1301") == 0)
|
||||
gpio_direction_input(2);
|
||||
isp->irq_type = IRQF_TRIGGER_FALLING;
|
||||
}
|
||||
|
||||
isp->irq_type |= IRQF_SAMPLE_RANDOM;
|
||||
status = request_irq(isp->irq, isp1301_irq,
|
||||
status = request_irq(i2c->irq, isp1301_irq,
|
||||
isp->irq_type, DRIVER_NAME, isp);
|
||||
if (status < 0) {
|
||||
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
|
||||
isp->irq, status);
|
||||
#ifdef CONFIG_USB_OTG
|
||||
fail2:
|
||||
#endif
|
||||
i2c_detach_client(i2c);
|
||||
goto fail1;
|
||||
i2c->irq, status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
isp->otg.dev = &isp->client.dev;
|
||||
isp->otg.dev = &i2c->dev;
|
||||
isp->otg.label = DRIVER_NAME;
|
||||
|
||||
isp->otg.set_host = isp1301_set_host,
|
||||
@@ -1649,22 +1615,25 @@ fail2:
|
||||
status);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
kfree(isp);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int isp1301_scan_bus(struct i2c_adapter *bus)
|
||||
{
|
||||
if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
|
||||
| I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -EINVAL;
|
||||
return i2c_probe(bus, &addr_data, isp1301_probe);
|
||||
}
|
||||
static const struct i2c_device_id isp1301_id[] = {
|
||||
{ "isp1301_omap", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, isp1301_id);
|
||||
|
||||
static struct i2c_driver isp1301_driver = {
|
||||
.driver = {
|
||||
.name = "isp1301_omap",
|
||||
},
|
||||
.attach_adapter = isp1301_scan_bus,
|
||||
.detach_client = isp1301_detach_client,
|
||||
.probe = isp1301_probe,
|
||||
.remove = __exit_p(isp1301_remove),
|
||||
.id_table = isp1301_id,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@@ -456,14 +456,17 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
|
||||
|
||||
/* offsets 0..3 == GPIO1..GPIO4
|
||||
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
|
||||
* offset 6 == vibrator motor driver
|
||||
*/
|
||||
static void
|
||||
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
if (offset < 4)
|
||||
tps65010_set_gpio_out_value(offset + 1, value);
|
||||
else
|
||||
else if (offset < 6)
|
||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||
else
|
||||
tps65010_set_vib(value);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -477,8 +480,10 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
if (!(tps->outmask & (1 << offset)))
|
||||
return -EINVAL;
|
||||
tps65010_set_gpio_out_value(offset + 1, value);
|
||||
} else
|
||||
} else if (offset < 6)
|
||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||
else
|
||||
tps65010_set_vib(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -646,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
|
||||
tps->chip.get = tps65010_gpio_get;
|
||||
|
||||
tps->chip.base = board->base;
|
||||
tps->chip.ngpio = 6;
|
||||
tps->chip.ngpio = 7;
|
||||
tps->chip.can_sleep = 1;
|
||||
|
||||
status = gpiochip_add(&tps->chip);
|
||||
@@ -675,6 +680,7 @@ static const struct i2c_device_id tps65010_id[] = {
|
||||
{ "tps65011", TPS65011 },
|
||||
{ "tps65012", TPS65012 },
|
||||
{ "tps65013", TPS65013 },
|
||||
{ "tps65014", TPS65011 }, /* tps65011 charging at 6.5V max */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tps65010_id);
|
||||
|
||||
+34
-1
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
int res = 0, dummy;
|
||||
|
||||
/* Can't register until after driver model init */
|
||||
if (unlikely(WARN_ON(!i2c_bus_type.p)))
|
||||
return -EAGAIN;
|
||||
|
||||
mutex_init(&adap->bus_lock);
|
||||
mutex_init(&adap->clist_lock);
|
||||
INIT_LIST_HEAD(&adap->clients);
|
||||
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Can't register until after driver model init */
|
||||
if (unlikely(WARN_ON(!i2c_bus_type.p)))
|
||||
return -EAGAIN;
|
||||
|
||||
/* new style driver methods can't mix with legacy ones */
|
||||
if (is_newstyle_driver(driver)) {
|
||||
if (driver->attach_adapter || driver->detach_adapter
|
||||
@@ -978,7 +986,10 @@ static void __exit i2c_exit(void)
|
||||
bus_unregister(&i2c_bus_type);
|
||||
}
|
||||
|
||||
subsys_initcall(i2c_init);
|
||||
/* We must initialize early, because some subsystems register i2c drivers
|
||||
* in subsys_initcall() code, but are linked (and initialized) before i2c.
|
||||
*/
|
||||
postcore_initcall(i2c_init);
|
||||
module_exit(i2c_exit);
|
||||
|
||||
/* ----------------------------------------------------
|
||||
@@ -1676,6 +1687,28 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_write_word_data);
|
||||
|
||||
/**
|
||||
* i2c_smbus_process_call - SMBus "process call" protocol
|
||||
* @client: Handle to slave device
|
||||
* @command: Byte interpreted by slave
|
||||
* @value: 16-bit "word" being written
|
||||
*
|
||||
* This executes the SMBus "process call" protocol, returning negative errno
|
||||
* else a 16-bit unsigned "word" received from the device.
|
||||
*/
|
||||
s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int status;
|
||||
data.word = value;
|
||||
|
||||
status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
|
||||
I2C_SMBUS_WRITE, command,
|
||||
I2C_SMBUS_PROC_CALL, &data);
|
||||
return (status < 0) ? status : data.word;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_smbus_process_call);
|
||||
|
||||
/**
|
||||
* i2c_smbus_read_block_data - SMBus "block read" protocol
|
||||
* @client: Handle to slave device
|
||||
|
||||
Reference in New Issue
Block a user