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:
Коммит
278429cff8
|
@ -16,6 +16,9 @@ Supported adapters:
|
||||||
* VIA Technologies, Inc. CX700
|
* VIA Technologies, Inc. CX700
|
||||||
Datasheet: available on request and under NDA from VIA
|
Datasheet: available on request and under NDA from VIA
|
||||||
|
|
||||||
|
* VIA Technologies, Inc. VX800/VX820
|
||||||
|
Datasheet: available on http://linux.via.com.tw
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
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:3372 (VT8237S)
|
||||||
device 1106:3287 (VT8251)
|
device 1106:3287 (VT8251)
|
||||||
device 1106:8324 (CX700)
|
device 1106:8324 (CX700)
|
||||||
|
device 1106:8353 (VX800/VX820)
|
||||||
|
|
||||||
If none of these show up, you should look in the BIOS for settings like
|
If none of these show up, you should look in the BIOS for settings like
|
||||||
enable ACPI / SMBus or even USB.
|
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
|
VT8231), this driver supports I2C block transactions. Such transactions
|
||||||
are mainly useful to read from and write to EEPROMs.
|
are mainly useful to read from and write to EEPROMs.
|
||||||
|
|
||||||
The CX700 additionally appears to support SMBus PEC, although this driver
|
The CX700/VX800/VX820 additionally appears to support SMBus PEC, although
|
||||||
doesn't implement it yet.
|
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
|
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.
|
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
|
I2C device files are character device files with major device number 89
|
||||||
and a minor device number corresponding to the number assigned as
|
and a minor device number corresponding to the number assigned as
|
||||||
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
|
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
|
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
|
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
|
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
|
meant to be included from user-space programs. You obviously want
|
||||||
the second one here.
|
the second one here.
|
||||||
|
|
||||||
Now, you have to decide which adapter you want to access. You should
|
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
|
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
|
||||||
somewhat dynamically, so you can not even assume /dev/i2c-0 is the
|
Adapter numbers are assigned somewhat dynamically, so you can not
|
||||||
first adapter.
|
assume much about them. They can even change from one boot to the next.
|
||||||
|
|
||||||
Next thing, open the device file, as follows:
|
Next thing, open the device file, as follows:
|
||||||
|
|
||||||
int file;
|
int file;
|
||||||
int adapter_nr = 2; /* probably dynamically determined */
|
int adapter_nr = 2; /* probably dynamically determined */
|
||||||
char filename[20];
|
char filename[20];
|
||||||
|
|
||||||
sprintf(filename,"/dev/i2c-%d",adapter_nr);
|
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
|
||||||
if ((file = open(filename,O_RDWR)) < 0) {
|
file = open(filename, O_RDWR);
|
||||||
|
if (file < 0) {
|
||||||
/* ERROR HANDLING; you can check errno to see what went wrong */
|
/* ERROR HANDLING; you can check errno to see what went wrong */
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
When you have opened the device, you must specify with what device
|
When you have opened the device, you must specify with what device
|
||||||
address you want to communicate:
|
address you want to communicate:
|
||||||
|
|
||||||
int addr = 0x40; /* The I2C address */
|
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 */
|
/* ERROR HANDLING; you can check errno to see what went wrong */
|
||||||
exit(1);
|
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
|
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
|
I2C to communicate with your device. SMBus commands are preferred if
|
||||||
the device supports them. Both are illustrated below.
|
the device supports them. Both are illustrated below.
|
||||||
|
|
||||||
__u8 register = 0x10; /* Device register to access */
|
__u8 register = 0x10; /* Device register to access */
|
||||||
__s32 res;
|
__s32 res;
|
||||||
char buf[10];
|
char buf[10];
|
||||||
|
|
||||||
/* Using SMBus commands */
|
/* Using SMBus commands */
|
||||||
res = i2c_smbus_read_word_data(file,register);
|
res = i2c_smbus_read_word_data(file, register);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
/* ERROR HANDLING: i2c transaction failed */
|
/* ERROR HANDLING: i2c transaction failed */
|
||||||
} else {
|
} else {
|
||||||
/* res contains the read word */
|
/* res contains the read word */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Using I2C Write, equivalent of
|
/* 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[0] = register;
|
||||||
buf[1] = 0x43;
|
buf[1] = 0x43;
|
||||||
buf[2] = 0x65;
|
buf[2] = 0x65;
|
||||||
if ( write(file,buf,3) != 3) {
|
if (write(file, buf, 3) ! =3) {
|
||||||
/* ERROR HANDLING: i2c transaction failed */
|
/* ERROR HANDLING: i2c transaction failed */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
|
/* 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 */
|
/* ERROR HANDLING: i2c transaction failed */
|
||||||
} else {
|
} else {
|
||||||
/* buf[0] contains the read byte */
|
/* 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
|
IMPORTANT: because of the use of inline functions, you *have* to use
|
||||||
'-O' or some variation when you compile your program!
|
'-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
|
Full interface description
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
The following IOCTLs are defined and fully supported
|
The following IOCTLs are defined:
|
||||||
(see also i2c-dev.h):
|
|
||||||
|
|
||||||
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
|
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
|
argument (except for 10 bit addresses, passed in the 10 lower bits in this
|
||||||
case).
|
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
|
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
|
addresses if select equals 0. Default 0. This request is only valid
|
||||||
if the adapter has I2C_FUNC_10BIT_ADDR.
|
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
|
Selects SMBus PEC (packet error checking) generation and verification
|
||||||
if select not equals 0, disables if select equals 0. Default 0.
|
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
|
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
|
the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
|
||||||
doesn't have any effect.
|
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.
|
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.
|
Do combined read/write transaction without stop in between.
|
||||||
Only valid if the adapter has I2C_FUNC_I2C. The argument is
|
Only valid if the adapter has I2C_FUNC_I2C. The argument is
|
||||||
a pointer to a
|
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
|
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.
|
set in each message, overriding the values set with the above ioctl's.
|
||||||
|
|
||||||
|
ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
|
||||||
Other values are NOT supported at this moment, except for I2C_SMBUS,
|
Not meant to be called directly; instead, use the access functions
|
||||||
which you should never directly call; instead, use the access functions
|
below.
|
||||||
below.
|
|
||||||
|
|
||||||
You can do plain i2c transactions by using read(2) and write(2) calls.
|
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
|
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
|
returns the number of values read. The block buffers need not be longer
|
||||||
than 32 bytes.
|
than 32 bytes.
|
||||||
|
|
||||||
The above functions are all macros, that resolve to calls to the
|
The above functions are all inline functions, that resolve to calls to
|
||||||
i2c_smbus_access function, that on its turn calls a specific ioctl
|
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
|
with the data in a specific format. Read the source code if you
|
||||||
want to know what happens behind the screens.
|
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
|
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
|
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.
|
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_read_word_data(struct i2c_client * client, u8 command);
|
||||||
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
|
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
|
||||||
u8 command, u16 value);
|
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,
|
extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
|
||||||
u8 command, u8 *values);
|
u8 command, u8 *values);
|
||||||
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
|
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:
|
be added back later if needed:
|
||||||
|
|
||||||
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
|
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,
|
extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
|
||||||
u8 command, u8 length,
|
u8 command, u8 length,
|
||||||
u8 *values)
|
u8 *values)
|
||||||
|
|
|
@ -476,6 +476,10 @@ static struct i2c_board_info __initdata h3_i2c_board_info[] = {
|
||||||
I2C_BOARD_INFO("tps65013", 0x48),
|
I2C_BOARD_INFO("tps65013", 0x48),
|
||||||
/* .irq = OMAP_GPIO_IRQ(??), */
|
/* .irq = OMAP_GPIO_IRQ(??), */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
I2C_BOARD_INFO("isp1301_omap", 0x2d),
|
||||||
|
.irq = OMAP_GPIO_IRQ(14),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
|
static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/mtd/partitions.h>
|
#include <linux/mtd/partitions.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
@ -391,6 +392,13 @@ static struct omap_board_config_kernel h4_config[] = {
|
||||||
{ OMAP_TAG_LCD, &h4_lcd_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)
|
static void __init omap_h4_init(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -411,6 +419,9 @@ static void __init omap_h4_init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#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));
|
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
|
||||||
omap_board_config = h4_config;
|
omap_board_config = h4_config;
|
||||||
omap_board_config_size = ARRAY_SIZE(h4_config);
|
omap_board_config_size = ARRAY_SIZE(h4_config);
|
||||||
|
|
|
@ -175,11 +175,11 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
|
||||||
* Data structures and manipulation thereof
|
* Data structures and manipulation thereof
|
||||||
* --------------------------------------------------------------------- */
|
* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
|
|
||||||
the driver field to differentiate between I2C and ISA chips. */
|
|
||||||
struct dme1737_data {
|
struct dme1737_data {
|
||||||
struct i2c_client client;
|
struct i2c_client *client; /* for I2C devices only */
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
|
const char *name;
|
||||||
|
unsigned int addr; /* for ISA devices only */
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
int valid; /* !=0 if following fields are valid */
|
int valid; /* !=0 if following fields are valid */
|
||||||
|
@ -512,11 +512,12 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
|
||||||
* before calling dme1737_read or dme1737_write.
|
* before calling dme1737_read or dme1737_write.
|
||||||
* --------------------------------------------------------------------- */
|
* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
static u8 dme1737_read(struct i2c_client *client, u8 reg)
|
static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
|
||||||
{
|
{
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
s32 val;
|
s32 val;
|
||||||
|
|
||||||
if (client->driver) { /* I2C device */
|
if (client) { /* I2C device */
|
||||||
val = i2c_smbus_read_byte_data(client, reg);
|
val = i2c_smbus_read_byte_data(client, reg);
|
||||||
|
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
|
@ -525,18 +526,19 @@ static u8 dme1737_read(struct i2c_client *client, u8 reg)
|
||||||
"maintainer.\n", reg);
|
"maintainer.\n", reg);
|
||||||
}
|
}
|
||||||
} else { /* ISA device */
|
} else { /* ISA device */
|
||||||
outb(reg, client->addr);
|
outb(reg, data->addr);
|
||||||
val = inb(client->addr + 1);
|
val = inb(data->addr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
|
static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
|
||||||
{
|
{
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
s32 res = 0;
|
s32 res = 0;
|
||||||
|
|
||||||
if (client->driver) { /* I2C device */
|
if (client) { /* I2C device */
|
||||||
res = i2c_smbus_write_byte_data(client, reg, val);
|
res = i2c_smbus_write_byte_data(client, reg, val);
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
|
@ -545,8 +547,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
|
||||||
"maintainer.\n", reg);
|
"maintainer.\n", reg);
|
||||||
}
|
}
|
||||||
} else { /* ISA device */
|
} else { /* ISA device */
|
||||||
outb(reg, client->addr);
|
outb(reg, data->addr);
|
||||||
outb(val, client->addr + 1);
|
outb(val, data->addr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -555,7 +557,6 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
|
||||||
static struct dme1737_data *dme1737_update_device(struct device *dev)
|
static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
int ix;
|
int ix;
|
||||||
u8 lsb[5];
|
u8 lsb[5];
|
||||||
|
|
||||||
|
@ -563,7 +564,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
|
|
||||||
/* Enable a Vbat monitoring cycle every 10 mins */
|
/* Enable a Vbat monitoring cycle every 10 mins */
|
||||||
if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
|
if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
|
||||||
dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
|
dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
|
||||||
DME1737_REG_CONFIG) | 0x10);
|
DME1737_REG_CONFIG) | 0x10);
|
||||||
data->last_vbat = jiffies;
|
data->last_vbat = jiffies;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +572,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
/* Sample register contents every 1 sec */
|
/* Sample register contents every 1 sec */
|
||||||
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
||||||
if (data->type != sch5027) {
|
if (data->type != sch5027) {
|
||||||
data->vid = dme1737_read(client, DME1737_REG_VID) &
|
data->vid = dme1737_read(data, DME1737_REG_VID) &
|
||||||
0x3f;
|
0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,11 +581,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
/* Voltage inputs are stored as 16 bit values even
|
/* Voltage inputs are stored as 16 bit values even
|
||||||
* though they have only 12 bits resolution. This is
|
* though they have only 12 bits resolution. This is
|
||||||
* to make it consistent with the temp inputs. */
|
* to make it consistent with the temp inputs. */
|
||||||
data->in[ix] = dme1737_read(client,
|
data->in[ix] = dme1737_read(data,
|
||||||
DME1737_REG_IN(ix)) << 8;
|
DME1737_REG_IN(ix)) << 8;
|
||||||
data->in_min[ix] = dme1737_read(client,
|
data->in_min[ix] = dme1737_read(data,
|
||||||
DME1737_REG_IN_MIN(ix));
|
DME1737_REG_IN_MIN(ix));
|
||||||
data->in_max[ix] = dme1737_read(client,
|
data->in_max[ix] = dme1737_read(data,
|
||||||
DME1737_REG_IN_MAX(ix));
|
DME1737_REG_IN_MAX(ix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,14 +596,14 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
* to take advantage of implicit conversions between
|
* to take advantage of implicit conversions between
|
||||||
* register values (2's complement) and temp values
|
* register values (2's complement) and temp values
|
||||||
* (signed decimal). */
|
* (signed decimal). */
|
||||||
data->temp[ix] = dme1737_read(client,
|
data->temp[ix] = dme1737_read(data,
|
||||||
DME1737_REG_TEMP(ix)) << 8;
|
DME1737_REG_TEMP(ix)) << 8;
|
||||||
data->temp_min[ix] = dme1737_read(client,
|
data->temp_min[ix] = dme1737_read(data,
|
||||||
DME1737_REG_TEMP_MIN(ix));
|
DME1737_REG_TEMP_MIN(ix));
|
||||||
data->temp_max[ix] = dme1737_read(client,
|
data->temp_max[ix] = dme1737_read(data,
|
||||||
DME1737_REG_TEMP_MAX(ix));
|
DME1737_REG_TEMP_MAX(ix));
|
||||||
if (data->type != sch5027) {
|
if (data->type != sch5027) {
|
||||||
data->temp_offset[ix] = dme1737_read(client,
|
data->temp_offset[ix] = dme1737_read(data,
|
||||||
DME1737_REG_TEMP_OFFSET(ix));
|
DME1737_REG_TEMP_OFFSET(ix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,7 +613,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
* which the registers are read (MSB first, then LSB) is
|
* which the registers are read (MSB first, then LSB) is
|
||||||
* important! */
|
* important! */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
|
||||||
lsb[ix] = dme1737_read(client,
|
lsb[ix] = dme1737_read(data,
|
||||||
DME1737_REG_IN_TEMP_LSB(ix));
|
DME1737_REG_IN_TEMP_LSB(ix));
|
||||||
}
|
}
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
||||||
|
@ -631,19 +632,19 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
if (!(data->has_fan & (1 << ix))) {
|
if (!(data->has_fan & (1 << ix))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
data->fan[ix] = dme1737_read(client,
|
data->fan[ix] = dme1737_read(data,
|
||||||
DME1737_REG_FAN(ix));
|
DME1737_REG_FAN(ix));
|
||||||
data->fan[ix] |= dme1737_read(client,
|
data->fan[ix] |= dme1737_read(data,
|
||||||
DME1737_REG_FAN(ix) + 1) << 8;
|
DME1737_REG_FAN(ix) + 1) << 8;
|
||||||
data->fan_min[ix] = dme1737_read(client,
|
data->fan_min[ix] = dme1737_read(data,
|
||||||
DME1737_REG_FAN_MIN(ix));
|
DME1737_REG_FAN_MIN(ix));
|
||||||
data->fan_min[ix] |= dme1737_read(client,
|
data->fan_min[ix] |= dme1737_read(data,
|
||||||
DME1737_REG_FAN_MIN(ix) + 1) << 8;
|
DME1737_REG_FAN_MIN(ix) + 1) << 8;
|
||||||
data->fan_opt[ix] = dme1737_read(client,
|
data->fan_opt[ix] = dme1737_read(data,
|
||||||
DME1737_REG_FAN_OPT(ix));
|
DME1737_REG_FAN_OPT(ix));
|
||||||
/* fan_max exists only for fan[5-6] */
|
/* fan_max exists only for fan[5-6] */
|
||||||
if (ix > 3) {
|
if (ix > 3) {
|
||||||
data->fan_max[ix - 4] = dme1737_read(client,
|
data->fan_max[ix - 4] = dme1737_read(data,
|
||||||
DME1737_REG_FAN_MAX(ix));
|
DME1737_REG_FAN_MAX(ix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,63 +656,63 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
if (!(data->has_pwm & (1 << ix))) {
|
if (!(data->has_pwm & (1 << ix))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
data->pwm[ix] = dme1737_read(client,
|
data->pwm[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM(ix));
|
DME1737_REG_PWM(ix));
|
||||||
data->pwm_freq[ix] = dme1737_read(client,
|
data->pwm_freq[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_FREQ(ix));
|
DME1737_REG_PWM_FREQ(ix));
|
||||||
/* pwm_config and pwm_min exist only for pwm[1-3] */
|
/* pwm_config and pwm_min exist only for pwm[1-3] */
|
||||||
if (ix < 3) {
|
if (ix < 3) {
|
||||||
data->pwm_config[ix] = dme1737_read(client,
|
data->pwm_config[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix));
|
DME1737_REG_PWM_CONFIG(ix));
|
||||||
data->pwm_min[ix] = dme1737_read(client,
|
data->pwm_min[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_MIN(ix));
|
DME1737_REG_PWM_MIN(ix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
|
||||||
data->pwm_rr[ix] = dme1737_read(client,
|
data->pwm_rr[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(ix));
|
DME1737_REG_PWM_RR(ix));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Thermal zone registers */
|
/* Thermal zone registers */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
|
||||||
data->zone_low[ix] = dme1737_read(client,
|
data->zone_low[ix] = dme1737_read(data,
|
||||||
DME1737_REG_ZONE_LOW(ix));
|
DME1737_REG_ZONE_LOW(ix));
|
||||||
data->zone_abs[ix] = dme1737_read(client,
|
data->zone_abs[ix] = dme1737_read(data,
|
||||||
DME1737_REG_ZONE_ABS(ix));
|
DME1737_REG_ZONE_ABS(ix));
|
||||||
}
|
}
|
||||||
if (data->type != sch5027) {
|
if (data->type != sch5027) {
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
||||||
data->zone_hyst[ix] = dme1737_read(client,
|
data->zone_hyst[ix] = dme1737_read(data,
|
||||||
DME1737_REG_ZONE_HYST(ix));
|
DME1737_REG_ZONE_HYST(ix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Alarm registers */
|
/* Alarm registers */
|
||||||
data->alarms = dme1737_read(client,
|
data->alarms = dme1737_read(data,
|
||||||
DME1737_REG_ALARM1);
|
DME1737_REG_ALARM1);
|
||||||
/* Bit 7 tells us if the other alarm registers are non-zero and
|
/* Bit 7 tells us if the other alarm registers are non-zero and
|
||||||
* therefore also need to be read */
|
* therefore also need to be read */
|
||||||
if (data->alarms & 0x80) {
|
if (data->alarms & 0x80) {
|
||||||
data->alarms |= dme1737_read(client,
|
data->alarms |= dme1737_read(data,
|
||||||
DME1737_REG_ALARM2) << 8;
|
DME1737_REG_ALARM2) << 8;
|
||||||
data->alarms |= dme1737_read(client,
|
data->alarms |= dme1737_read(data,
|
||||||
DME1737_REG_ALARM3) << 16;
|
DME1737_REG_ALARM3) << 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The ISA chips require explicit clearing of alarm bits.
|
/* The ISA chips require explicit clearing of alarm bits.
|
||||||
* Don't worry, an alarm will come back if the condition
|
* Don't worry, an alarm will come back if the condition
|
||||||
* that causes it still exists */
|
* that causes it still exists */
|
||||||
if (!client->driver) {
|
if (!data->client) {
|
||||||
if (data->alarms & 0xff0000) {
|
if (data->alarms & 0xff0000) {
|
||||||
dme1737_write(client, DME1737_REG_ALARM3,
|
dme1737_write(data, DME1737_REG_ALARM3,
|
||||||
0xff);
|
0xff);
|
||||||
}
|
}
|
||||||
if (data->alarms & 0xff00) {
|
if (data->alarms & 0xff00) {
|
||||||
dme1737_write(client, DME1737_REG_ALARM2,
|
dme1737_write(data, DME1737_REG_ALARM2,
|
||||||
0xff);
|
0xff);
|
||||||
}
|
}
|
||||||
if (data->alarms & 0xff) {
|
if (data->alarms & 0xff) {
|
||||||
dme1737_write(client, DME1737_REG_ALARM1,
|
dme1737_write(data, DME1737_REG_ALARM1,
|
||||||
0xff);
|
0xff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,7 +771,6 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
struct sensor_device_attribute_2
|
struct sensor_device_attribute_2
|
||||||
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
||||||
int ix = sensor_attr_2->index;
|
int ix = sensor_attr_2->index;
|
||||||
|
@ -781,12 +781,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_IN_MIN:
|
case SYS_IN_MIN:
|
||||||
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MIN(ix),
|
dme1737_write(data, DME1737_REG_IN_MIN(ix),
|
||||||
data->in_min[ix]);
|
data->in_min[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MAX:
|
case SYS_IN_MAX:
|
||||||
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MAX(ix),
|
dme1737_write(data, DME1737_REG_IN_MAX(ix),
|
||||||
data->in_max[ix]);
|
data->in_max[ix]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -850,7 +850,6 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
struct sensor_device_attribute_2
|
struct sensor_device_attribute_2
|
||||||
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
||||||
int ix = sensor_attr_2->index;
|
int ix = sensor_attr_2->index;
|
||||||
|
@ -861,17 +860,17 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_TEMP_MIN:
|
case SYS_TEMP_MIN:
|
||||||
data->temp_min[ix] = TEMP_TO_REG(val);
|
data->temp_min[ix] = TEMP_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
|
dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
|
||||||
data->temp_min[ix]);
|
data->temp_min[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_TEMP_MAX:
|
case SYS_TEMP_MAX:
|
||||||
data->temp_max[ix] = TEMP_TO_REG(val);
|
data->temp_max[ix] = TEMP_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
|
dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
|
||||||
data->temp_max[ix]);
|
data->temp_max[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_TEMP_OFFSET:
|
case SYS_TEMP_OFFSET:
|
||||||
data->temp_offset[ix] = TEMP_TO_REG(val);
|
data->temp_offset[ix] = TEMP_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
|
dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
|
||||||
data->temp_offset[ix]);
|
data->temp_offset[ix]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -939,7 +938,6 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
struct sensor_device_attribute_2
|
struct sensor_device_attribute_2
|
||||||
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
||||||
int ix = sensor_attr_2->index;
|
int ix = sensor_attr_2->index;
|
||||||
|
@ -950,37 +948,37 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
|
case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->zone_low[ix] = dme1737_read(client,
|
data->zone_low[ix] = dme1737_read(data,
|
||||||
DME1737_REG_ZONE_LOW(ix));
|
DME1737_REG_ZONE_LOW(ix));
|
||||||
/* Modify the temp hyst value */
|
/* Modify the temp hyst value */
|
||||||
data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
|
data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
|
||||||
TEMP_FROM_REG(data->zone_low[ix], 8) -
|
TEMP_FROM_REG(data->zone_low[ix], 8) -
|
||||||
val, ix, dme1737_read(client,
|
val, ix, dme1737_read(data,
|
||||||
DME1737_REG_ZONE_HYST(ix == 2)));
|
DME1737_REG_ZONE_HYST(ix == 2)));
|
||||||
dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
|
dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
|
||||||
data->zone_hyst[ix == 2]);
|
data->zone_hyst[ix == 2]);
|
||||||
break;
|
break;
|
||||||
case SYS_ZONE_AUTO_POINT1_TEMP:
|
case SYS_ZONE_AUTO_POINT1_TEMP:
|
||||||
data->zone_low[ix] = TEMP_TO_REG(val);
|
data->zone_low[ix] = TEMP_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
|
dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
|
||||||
data->zone_low[ix]);
|
data->zone_low[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_ZONE_AUTO_POINT2_TEMP:
|
case SYS_ZONE_AUTO_POINT2_TEMP:
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->zone_low[ix] = dme1737_read(client,
|
data->zone_low[ix] = dme1737_read(data,
|
||||||
DME1737_REG_ZONE_LOW(ix));
|
DME1737_REG_ZONE_LOW(ix));
|
||||||
/* Modify the temp range value (which is stored in the upper
|
/* Modify the temp range value (which is stored in the upper
|
||||||
* nibble of the pwm_freq register) */
|
* nibble of the pwm_freq register) */
|
||||||
data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
|
data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
|
||||||
TEMP_FROM_REG(data->zone_low[ix], 8),
|
TEMP_FROM_REG(data->zone_low[ix], 8),
|
||||||
dme1737_read(client,
|
dme1737_read(data,
|
||||||
DME1737_REG_PWM_FREQ(ix)));
|
DME1737_REG_PWM_FREQ(ix)));
|
||||||
dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
|
dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
|
||||||
data->pwm_freq[ix]);
|
data->pwm_freq[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_ZONE_AUTO_POINT3_TEMP:
|
case SYS_ZONE_AUTO_POINT3_TEMP:
|
||||||
data->zone_abs[ix] = TEMP_TO_REG(val);
|
data->zone_abs[ix] = TEMP_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
|
dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
|
||||||
data->zone_abs[ix]);
|
data->zone_abs[ix]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1046,7 +1044,6 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
struct sensor_device_attribute_2
|
struct sensor_device_attribute_2
|
||||||
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
||||||
int ix = sensor_attr_2->index;
|
int ix = sensor_attr_2->index;
|
||||||
|
@ -1060,21 +1057,21 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
||||||
data->fan_min[ix] = FAN_TO_REG(val, 0);
|
data->fan_min[ix] = FAN_TO_REG(val, 0);
|
||||||
} else {
|
} else {
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->fan_opt[ix] = dme1737_read(client,
|
data->fan_opt[ix] = dme1737_read(data,
|
||||||
DME1737_REG_FAN_OPT(ix));
|
DME1737_REG_FAN_OPT(ix));
|
||||||
/* Modify the fan min value */
|
/* Modify the fan min value */
|
||||||
data->fan_min[ix] = FAN_TO_REG(val,
|
data->fan_min[ix] = FAN_TO_REG(val,
|
||||||
FAN_TPC_FROM_REG(data->fan_opt[ix]));
|
FAN_TPC_FROM_REG(data->fan_opt[ix]));
|
||||||
}
|
}
|
||||||
dme1737_write(client, DME1737_REG_FAN_MIN(ix),
|
dme1737_write(data, DME1737_REG_FAN_MIN(ix),
|
||||||
data->fan_min[ix] & 0xff);
|
data->fan_min[ix] & 0xff);
|
||||||
dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
|
dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
|
||||||
data->fan_min[ix] >> 8);
|
data->fan_min[ix] >> 8);
|
||||||
break;
|
break;
|
||||||
case SYS_FAN_MAX:
|
case SYS_FAN_MAX:
|
||||||
/* Only valid for fan[5-6] */
|
/* Only valid for fan[5-6] */
|
||||||
data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
|
data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
|
||||||
dme1737_write(client, DME1737_REG_FAN_MAX(ix),
|
dme1737_write(data, DME1737_REG_FAN_MAX(ix),
|
||||||
data->fan_max[ix - 4]);
|
data->fan_max[ix - 4]);
|
||||||
break;
|
break;
|
||||||
case SYS_FAN_TYPE:
|
case SYS_FAN_TYPE:
|
||||||
|
@ -1086,9 +1083,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
||||||
val);
|
val);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
|
data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
|
||||||
DME1737_REG_FAN_OPT(ix)));
|
DME1737_REG_FAN_OPT(ix)));
|
||||||
dme1737_write(client, DME1737_REG_FAN_OPT(ix),
|
dme1737_write(data, DME1737_REG_FAN_OPT(ix),
|
||||||
data->fan_opt[ix]);
|
data->fan_opt[ix]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1185,7 +1182,6 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
|
||||||
struct sensor_device_attribute_2
|
struct sensor_device_attribute_2
|
||||||
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
|
||||||
int ix = sensor_attr_2->index;
|
int ix = sensor_attr_2->index;
|
||||||
|
@ -1196,12 +1192,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_PWM:
|
case SYS_PWM:
|
||||||
data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
|
data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
|
||||||
dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
|
dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_PWM_FREQ:
|
case SYS_PWM_FREQ:
|
||||||
data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
|
data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
|
||||||
DME1737_REG_PWM_FREQ(ix)));
|
DME1737_REG_PWM_FREQ(ix)));
|
||||||
dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
|
dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
|
||||||
data->pwm_freq[ix]);
|
data->pwm_freq[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_PWM_ENABLE:
|
case SYS_PWM_ENABLE:
|
||||||
|
@ -1214,7 +1210,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->pwm_config[ix] = dme1737_read(client,
|
data->pwm_config[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix));
|
DME1737_REG_PWM_CONFIG(ix));
|
||||||
if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
|
if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
|
||||||
/* Bail out if no change */
|
/* Bail out if no change */
|
||||||
|
@ -1226,14 +1222,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
|
data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
/* Save the current ramp rate state and disable it */
|
/* Save the current ramp rate state and disable it */
|
||||||
data->pwm_rr[ix > 0] = dme1737_read(client,
|
data->pwm_rr[ix > 0] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(ix > 0));
|
DME1737_REG_PWM_RR(ix > 0));
|
||||||
data->pwm_rr_en &= ~(1 << ix);
|
data->pwm_rr_en &= ~(1 << ix);
|
||||||
if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
|
if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
|
||||||
data->pwm_rr_en |= (1 << ix);
|
data->pwm_rr_en |= (1 << ix);
|
||||||
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
|
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
|
||||||
data->pwm_rr[ix > 0]);
|
data->pwm_rr[ix > 0]);
|
||||||
dme1737_write(client,
|
dme1737_write(data,
|
||||||
DME1737_REG_PWM_RR(ix > 0),
|
DME1737_REG_PWM_RR(ix > 0),
|
||||||
data->pwm_rr[ix > 0]);
|
data->pwm_rr[ix > 0]);
|
||||||
}
|
}
|
||||||
|
@ -1247,14 +1243,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
/* Turn fan fully on */
|
/* Turn fan fully on */
|
||||||
data->pwm_config[ix] = PWM_EN_TO_REG(0,
|
data->pwm_config[ix] = PWM_EN_TO_REG(0,
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* Turn on manual mode */
|
/* Turn on manual mode */
|
||||||
data->pwm_config[ix] = PWM_EN_TO_REG(1,
|
data->pwm_config[ix] = PWM_EN_TO_REG(1,
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
/* Change permissions of pwm[ix] to read-writeable */
|
/* Change permissions of pwm[ix] to read-writeable */
|
||||||
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
|
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
|
||||||
|
@ -1269,14 +1265,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
data->pwm_config[ix] = PWM_ACZ_TO_REG(
|
data->pwm_config[ix] = PWM_ACZ_TO_REG(
|
||||||
data->pwm_acz[ix],
|
data->pwm_acz[ix],
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
/* Enable PWM ramp rate if previously enabled */
|
/* Enable PWM ramp rate if previously enabled */
|
||||||
if (data->pwm_rr_en & (1 << ix)) {
|
if (data->pwm_rr_en & (1 << ix)) {
|
||||||
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
|
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
|
||||||
dme1737_read(client,
|
dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(ix > 0)));
|
DME1737_REG_PWM_RR(ix > 0)));
|
||||||
dme1737_write(client,
|
dme1737_write(data,
|
||||||
DME1737_REG_PWM_RR(ix > 0),
|
DME1737_REG_PWM_RR(ix > 0),
|
||||||
data->pwm_rr[ix > 0]);
|
data->pwm_rr[ix > 0]);
|
||||||
}
|
}
|
||||||
|
@ -1286,9 +1282,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
case SYS_PWM_RAMP_RATE:
|
case SYS_PWM_RAMP_RATE:
|
||||||
/* Only valid for pwm[1-3] */
|
/* Only valid for pwm[1-3] */
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->pwm_config[ix] = dme1737_read(client,
|
data->pwm_config[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix));
|
DME1737_REG_PWM_CONFIG(ix));
|
||||||
data->pwm_rr[ix > 0] = dme1737_read(client,
|
data->pwm_rr[ix > 0] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(ix > 0));
|
DME1737_REG_PWM_RR(ix > 0));
|
||||||
/* Set the ramp rate value */
|
/* Set the ramp rate value */
|
||||||
if (val > 0) {
|
if (val > 0) {
|
||||||
|
@ -1301,7 +1297,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
|
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
|
||||||
data->pwm_rr[ix > 0]);
|
data->pwm_rr[ix > 0]);
|
||||||
}
|
}
|
||||||
dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
|
dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
|
||||||
data->pwm_rr[ix > 0]);
|
data->pwm_rr[ix > 0]);
|
||||||
break;
|
break;
|
||||||
case SYS_PWM_AUTO_CHANNELS_ZONE:
|
case SYS_PWM_AUTO_CHANNELS_ZONE:
|
||||||
|
@ -1315,14 +1311,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->pwm_config[ix] = dme1737_read(client,
|
data->pwm_config[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix));
|
DME1737_REG_PWM_CONFIG(ix));
|
||||||
if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
|
if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
|
||||||
/* PWM is already in auto mode so update the temp
|
/* PWM is already in auto mode so update the temp
|
||||||
* channel assignment */
|
* channel assignment */
|
||||||
data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
|
data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
} else {
|
} else {
|
||||||
/* PWM is not in auto mode so we save the temp
|
/* PWM is not in auto mode so we save the temp
|
||||||
|
@ -1333,7 +1329,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
case SYS_PWM_AUTO_PWM_MIN:
|
case SYS_PWM_AUTO_PWM_MIN:
|
||||||
/* Only valid for pwm[1-3] */
|
/* Only valid for pwm[1-3] */
|
||||||
/* Refresh the cache */
|
/* Refresh the cache */
|
||||||
data->pwm_min[ix] = dme1737_read(client,
|
data->pwm_min[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_MIN(ix));
|
DME1737_REG_PWM_MIN(ix));
|
||||||
/* There are only 2 values supported for the auto_pwm_min
|
/* There are only 2 values supported for the auto_pwm_min
|
||||||
* value: 0 or auto_point1_pwm. So if the temperature drops
|
* value: 0 or auto_point1_pwm. So if the temperature drops
|
||||||
|
@ -1341,20 +1337,20 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
* off or runs at auto_point1_pwm duty-cycle. */
|
* off or runs at auto_point1_pwm duty-cycle. */
|
||||||
if (val > ((data->pwm_min[ix] + 1) / 2)) {
|
if (val > ((data->pwm_min[ix] + 1) / 2)) {
|
||||||
data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
|
data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
|
||||||
dme1737_read(client,
|
dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(0)));
|
DME1737_REG_PWM_RR(0)));
|
||||||
} else {
|
} else {
|
||||||
data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
|
data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
|
||||||
dme1737_read(client,
|
dme1737_read(data,
|
||||||
DME1737_REG_PWM_RR(0)));
|
DME1737_REG_PWM_RR(0)));
|
||||||
}
|
}
|
||||||
dme1737_write(client, DME1737_REG_PWM_RR(0),
|
dme1737_write(data, DME1737_REG_PWM_RR(0),
|
||||||
data->pwm_rr[0]);
|
data->pwm_rr[0]);
|
||||||
break;
|
break;
|
||||||
case SYS_PWM_AUTO_POINT1_PWM:
|
case SYS_PWM_AUTO_POINT1_PWM:
|
||||||
/* Only valid for pwm[1-3] */
|
/* Only valid for pwm[1-3] */
|
||||||
data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
|
data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
|
||||||
dme1737_write(client, DME1737_REG_PWM_MIN(ix),
|
dme1737_write(data, DME1737_REG_PWM_MIN(ix),
|
||||||
data->pwm_min[ix]);
|
data->pwm_min[ix]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1402,7 +1398,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", data->client.name);
|
return sprintf(buf, "%s\n", data->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
|
@ -1908,7 +1904,7 @@ static void dme1737_remove_files(struct device *dev)
|
||||||
|
|
||||||
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
||||||
|
|
||||||
if (!data->client.driver) {
|
if (!data->client) {
|
||||||
sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
|
sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1919,7 +1915,7 @@ static int dme1737_create_files(struct device *dev)
|
||||||
int err, ix;
|
int err, ix;
|
||||||
|
|
||||||
/* Create a name attribute for ISA devices */
|
/* Create a name attribute for ISA devices */
|
||||||
if (!data->client.driver &&
|
if (!data->client &&
|
||||||
(err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
|
(err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@ -2013,14 +2009,14 @@ exit:
|
||||||
static int dme1737_init_device(struct device *dev)
|
static int dme1737_init_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = dev_get_drvdata(dev);
|
struct dme1737_data *data = dev_get_drvdata(dev);
|
||||||
struct i2c_client *client = &data->client;
|
struct i2c_client *client = data->client;
|
||||||
int ix;
|
int ix;
|
||||||
u8 reg;
|
u8 reg;
|
||||||
|
|
||||||
/* Point to the right nominal voltages array */
|
/* Point to the right nominal voltages array */
|
||||||
data->in_nominal = IN_NOMINAL(data->type);
|
data->in_nominal = IN_NOMINAL(data->type);
|
||||||
|
|
||||||
data->config = dme1737_read(client, DME1737_REG_CONFIG);
|
data->config = dme1737_read(data, DME1737_REG_CONFIG);
|
||||||
/* Inform if part is not monitoring/started */
|
/* Inform if part is not monitoring/started */
|
||||||
if (!(data->config & 0x01)) {
|
if (!(data->config & 0x01)) {
|
||||||
if (!force_start) {
|
if (!force_start) {
|
||||||
|
@ -2032,7 +2028,7 @@ static int dme1737_init_device(struct device *dev)
|
||||||
|
|
||||||
/* Force monitoring */
|
/* Force monitoring */
|
||||||
data->config |= 0x01;
|
data->config |= 0x01;
|
||||||
dme1737_write(client, DME1737_REG_CONFIG, data->config);
|
dme1737_write(data, DME1737_REG_CONFIG, data->config);
|
||||||
}
|
}
|
||||||
/* Inform if part is not ready */
|
/* Inform if part is not ready */
|
||||||
if (!(data->config & 0x04)) {
|
if (!(data->config & 0x04)) {
|
||||||
|
@ -2041,8 +2037,8 @@ static int dme1737_init_device(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine which optional fan and pwm features are enabled/present */
|
/* Determine which optional fan and pwm features are enabled/present */
|
||||||
if (client->driver) { /* I2C chip */
|
if (client) { /* I2C chip */
|
||||||
data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
|
data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
|
||||||
/* Check if optional fan3 input is enabled */
|
/* Check if optional fan3 input is enabled */
|
||||||
if (data->config2 & 0x04) {
|
if (data->config2 & 0x04) {
|
||||||
data->has_fan |= (1 << 2);
|
data->has_fan |= (1 << 2);
|
||||||
|
@ -2051,7 +2047,7 @@ static int dme1737_init_device(struct device *dev)
|
||||||
/* Fan4 and pwm3 are only available if the client's I2C address
|
/* Fan4 and pwm3 are only available if the client's I2C address
|
||||||
* is the default 0x2e. Otherwise the I/Os associated with
|
* is the default 0x2e. Otherwise the I/Os associated with
|
||||||
* these functions are used for addr enable/select. */
|
* these functions are used for addr enable/select. */
|
||||||
if (data->client.addr == 0x2e) {
|
if (client->addr == 0x2e) {
|
||||||
data->has_fan |= (1 << 3);
|
data->has_fan |= (1 << 3);
|
||||||
data->has_pwm |= (1 << 2);
|
data->has_pwm |= (1 << 2);
|
||||||
}
|
}
|
||||||
|
@ -2086,16 +2082,16 @@ static int dme1737_init_device(struct device *dev)
|
||||||
(data->has_fan & (1 << 4)) ? "yes" : "no",
|
(data->has_fan & (1 << 4)) ? "yes" : "no",
|
||||||
(data->has_fan & (1 << 5)) ? "yes" : "no");
|
(data->has_fan & (1 << 5)) ? "yes" : "no");
|
||||||
|
|
||||||
reg = dme1737_read(client, DME1737_REG_TACH_PWM);
|
reg = dme1737_read(data, DME1737_REG_TACH_PWM);
|
||||||
/* Inform if fan-to-pwm mapping differs from the default */
|
/* Inform if fan-to-pwm mapping differs from the default */
|
||||||
if (client->driver && reg != 0xa4) { /* I2C chip */
|
if (client && reg != 0xa4) { /* I2C chip */
|
||||||
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
||||||
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
|
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
|
||||||
"fan4->pwm%d. Please report to the driver "
|
"fan4->pwm%d. Please report to the driver "
|
||||||
"maintainer.\n",
|
"maintainer.\n",
|
||||||
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
|
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
|
||||||
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
|
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
|
||||||
} else if (!client->driver && reg != 0x24) { /* ISA chip */
|
} else if (!client && reg != 0x24) { /* ISA chip */
|
||||||
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
||||||
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
|
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
|
||||||
"Please report to the driver maintainer.\n",
|
"Please report to the driver maintainer.\n",
|
||||||
|
@ -2108,7 +2104,7 @@ static int dme1737_init_device(struct device *dev)
|
||||||
* disabled). */
|
* disabled). */
|
||||||
if (!(data->config & 0x02)) {
|
if (!(data->config & 0x02)) {
|
||||||
for (ix = 0; ix < 3; ix++) {
|
for (ix = 0; ix < 3; ix++) {
|
||||||
data->pwm_config[ix] = dme1737_read(client,
|
data->pwm_config[ix] = dme1737_read(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix));
|
DME1737_REG_PWM_CONFIG(ix));
|
||||||
if ((data->has_pwm & (1 << ix)) &&
|
if ((data->has_pwm & (1 << ix)) &&
|
||||||
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
|
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
|
||||||
|
@ -2116,8 +2112,8 @@ static int dme1737_init_device(struct device *dev)
|
||||||
"manual mode.\n", ix + 1);
|
"manual mode.\n", ix + 1);
|
||||||
data->pwm_config[ix] = PWM_EN_TO_REG(1,
|
data->pwm_config[ix] = PWM_EN_TO_REG(1,
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
dme1737_write(client, DME1737_REG_PWM(ix), 0);
|
dme1737_write(data, DME1737_REG_PWM(ix), 0);
|
||||||
dme1737_write(client,
|
dme1737_write(data,
|
||||||
DME1737_REG_PWM_CONFIG(ix),
|
DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
}
|
}
|
||||||
|
@ -2191,37 +2187,24 @@ exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
int kind)
|
static int dme1737_i2c_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
|
struct device *dev = &adapter->dev;
|
||||||
u8 company, verstep = 0;
|
u8 company, verstep = 0;
|
||||||
struct i2c_client *client;
|
|
||||||
struct dme1737_data *data;
|
|
||||||
struct device *dev;
|
|
||||||
int err = 0;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &dme1737_i2c_driver;
|
|
||||||
dev = &client->dev;
|
|
||||||
|
|
||||||
/* A negative kind means that the driver was loaded with no force
|
/* A negative kind means that the driver was loaded with no force
|
||||||
* parameter (default), so we must identify the chip. */
|
* parameter (default), so we must identify the chip. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
company = dme1737_read(client, DME1737_REG_COMPANY);
|
company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
|
||||||
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
|
verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
|
||||||
|
|
||||||
if (company == DME1737_COMPANY_SMSC &&
|
if (company == DME1737_COMPANY_SMSC &&
|
||||||
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
|
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
|
||||||
|
@ -2230,8 +2213,7 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
||||||
verstep == SCH5027_VERSTEP) {
|
verstep == SCH5027_VERSTEP) {
|
||||||
kind = sch5027;
|
kind = sch5027;
|
||||||
} else {
|
} else {
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit_kfree;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2241,32 +2223,44 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
||||||
kind = dme1737;
|
kind = dme1737;
|
||||||
name = "dme1737";
|
name = "dme1737";
|
||||||
}
|
}
|
||||||
data->type = kind;
|
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global
|
|
||||||
* list */
|
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client))) {
|
|
||||||
goto exit_kfree;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
|
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
|
||||||
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
|
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
|
||||||
verstep);
|
verstep);
|
||||||
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dme1737_i2c_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct dme1737_data *data;
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
data->type = id->driver_data;
|
||||||
|
data->client = client;
|
||||||
|
data->name = client->name;
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Initialize the DME1737 chip */
|
/* Initialize the DME1737 chip */
|
||||||
if ((err = dme1737_init_device(dev))) {
|
if ((err = dme1737_init_device(dev))) {
|
||||||
dev_err(dev, "Failed to initialize device.\n");
|
dev_err(dev, "Failed to initialize device.\n");
|
||||||
goto exit_detach;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create sysfs files */
|
/* Create sysfs files */
|
||||||
if ((err = dme1737_create_files(dev))) {
|
if ((err = dme1737_create_files(dev))) {
|
||||||
dev_err(dev, "Failed to create sysfs files.\n");
|
dev_err(dev, "Failed to create sysfs files.\n");
|
||||||
goto exit_detach;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register device */
|
/* Register device */
|
||||||
|
@ -2281,45 +2275,40 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
dme1737_remove_files(dev);
|
dme1737_remove_files(dev);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_kfree:
|
exit_kfree:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
|
static int dme1737_i2c_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dme1737_i2c_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct dme1737_data *data = i2c_get_clientdata(client);
|
struct dme1737_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
dme1737_remove_files(&client->dev);
|
dme1737_remove_files(&client->dev);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client))) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id dme1737_id[] = {
|
||||||
|
{ "dme1737", dme1737 },
|
||||||
|
{ "sch5027", sch5027 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, dme1737_id);
|
||||||
|
|
||||||
static struct i2c_driver dme1737_i2c_driver = {
|
static struct i2c_driver dme1737_i2c_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "dme1737",
|
.name = "dme1737",
|
||||||
},
|
},
|
||||||
.attach_adapter = dme1737_i2c_attach_adapter,
|
.probe = dme1737_i2c_probe,
|
||||||
.detach_client = dme1737_i2c_detach_client,
|
.remove = dme1737_i2c_remove,
|
||||||
|
.id_table = dme1737_id,
|
||||||
|
.detect = dme1737_i2c_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
|
@ -2403,7 +2392,6 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
u8 company, device;
|
u8 company, device;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct i2c_client *client;
|
|
||||||
struct dme1737_data *data;
|
struct dme1737_data *data;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int err;
|
int err;
|
||||||
|
@ -2422,15 +2410,13 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
||||||
goto exit_release_region;
|
goto exit_release_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
data->addr = res->start;
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = res->start;
|
|
||||||
platform_set_drvdata(pdev, data);
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
/* Skip chip detection if module is loaded with force_id parameter */
|
/* Skip chip detection if module is loaded with force_id parameter */
|
||||||
if (!force_id) {
|
if (!force_id) {
|
||||||
company = dme1737_read(client, DME1737_REG_COMPANY);
|
company = dme1737_read(data, DME1737_REG_COMPANY);
|
||||||
device = dme1737_read(client, DME1737_REG_DEVICE);
|
device = dme1737_read(data, DME1737_REG_DEVICE);
|
||||||
|
|
||||||
if (!((company == DME1737_COMPANY_SMSC) &&
|
if (!((company == DME1737_COMPANY_SMSC) &&
|
||||||
(device == SCH311X_DEVICE))) {
|
(device == SCH311X_DEVICE))) {
|
||||||
|
@ -2441,10 +2427,10 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
||||||
data->type = sch311x;
|
data->type = sch311x;
|
||||||
|
|
||||||
/* Fill in the remaining client fields and initialize the mutex */
|
/* Fill in the remaining client fields and initialize the mutex */
|
||||||
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
|
data->name = "sch311x";
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
|
dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
if ((err = dme1737_init_device(dev))) {
|
if ((err = dme1737_init_device(dev))) {
|
||||||
|
@ -2485,7 +2471,7 @@ static int __devexit dme1737_isa_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
dme1737_remove_files(&pdev->dev);
|
dme1737_remove_files(&pdev->dev);
|
||||||
release_region(data->client.addr, DME1737_EXTENT);
|
release_region(data->addr, DME1737_EXTENT);
|
||||||
platform_set_drvdata(pdev, NULL);
|
platform_set_drvdata(pdev, NULL);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ config I2C_AMD756
|
||||||
|
|
||||||
config I2C_AMD756_S4882
|
config I2C_AMD756_S4882
|
||||||
tristate "SMBus multiplexing on the Tyan S4882"
|
tristate "SMBus multiplexing on the Tyan S4882"
|
||||||
depends on I2C_AMD756 && EXPERIMENTAL
|
depends on I2C_AMD756 && X86 && EXPERIMENTAL
|
||||||
help
|
help
|
||||||
Enabling this option will add specific SMBus support for the Tyan
|
Enabling this option will add specific SMBus support for the Tyan
|
||||||
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
||||||
|
@ -148,7 +148,7 @@ config I2C_NFORCE2
|
||||||
|
|
||||||
config I2C_NFORCE2_S4985
|
config I2C_NFORCE2_S4985
|
||||||
tristate "SMBus multiplexing on the Tyan S4985"
|
tristate "SMBus multiplexing on the Tyan S4985"
|
||||||
depends on I2C_NFORCE2 && EXPERIMENTAL
|
depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
|
||||||
help
|
help
|
||||||
Enabling this option will add specific SMBus support for the Tyan
|
Enabling this option will add specific SMBus support for the Tyan
|
||||||
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
|
||||||
|
@ -209,7 +209,7 @@ config I2C_VIA
|
||||||
will be called i2c-via.
|
will be called i2c-via.
|
||||||
|
|
||||||
config I2C_VIAPRO
|
config I2C_VIAPRO
|
||||||
tristate "VIA VT82C596/82C686/82xx and CX700"
|
tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the VIA
|
If you say yes to this option, support will be included for the VIA
|
||||||
|
@ -223,6 +223,8 @@ config I2C_VIAPRO
|
||||||
VT8237R/A/S
|
VT8237R/A/S
|
||||||
VT8251
|
VT8251
|
||||||
CX700
|
CX700
|
||||||
|
VX800
|
||||||
|
VX820
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called i2c-viapro.
|
will be called i2c-viapro.
|
||||||
|
@ -330,6 +332,18 @@ config I2C_GPIO
|
||||||
This is a very simple bitbanging I2C driver utilizing the
|
This is a very simple bitbanging I2C driver utilizing the
|
||||||
arch-neutral GPIO API to control the SCL and SDA lines.
|
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
|
config I2C_IBM_IIC
|
||||||
tristate "IBM PPC 4xx on-chip I2C interface"
|
tristate "IBM PPC 4xx on-chip I2C interface"
|
||||||
depends on 4xx
|
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_CPM) += i2c-cpm.o
|
||||||
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.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_IBM_IIC) += i2c-ibm_iic.o
|
||||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||||
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.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)
|
static int __devinit i2c_parport_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int err;
|
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) */
|
/* Reset hardware to a sane state (SCL and SDA high) */
|
||||||
parport_setsda(NULL, 1);
|
parport_setsda(NULL, 1);
|
||||||
|
@ -138,29 +133,19 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
parport_adapter.dev.parent = &pdev->dev;
|
parport_adapter.dev.parent = &pdev->dev;
|
||||||
err = i2c_bit_add_bus(&parport_adapter);
|
err = i2c_bit_add_bus(&parport_adapter);
|
||||||
if (err) {
|
if (err)
|
||||||
dev_err(&pdev->dev, "Unable to register with I2C\n");
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devexit i2c_parport_remove(struct platform_device *pdev)
|
static int __devexit i2c_parport_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
i2c_del_adapter(&parport_adapter);
|
i2c_del_adapter(&parport_adapter);
|
||||||
|
|
||||||
/* Un-init if needed (power off...) */
|
/* Un-init if needed (power off...) */
|
||||||
if (adapter_parm[type].init.val)
|
if (adapter_parm[type].init.val)
|
||||||
line_set(0, &adapter_parm[type].init);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,12 +160,6 @@ static struct platform_driver i2c_parport_driver = {
|
||||||
|
|
||||||
static int __init i2c_parport_device_add(u16 address)
|
static int __init i2c_parport_device_add(u16 address)
|
||||||
{
|
{
|
||||||
struct resource res = {
|
|
||||||
.start = address,
|
|
||||||
.end = address + 2,
|
|
||||||
.name = DRVNAME,
|
|
||||||
.flags = IORESOURCE_IO,
|
|
||||||
};
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pdev = platform_device_alloc(DRVNAME, -1);
|
pdev = platform_device_alloc(DRVNAME, -1);
|
||||||
|
@ -190,13 +169,6 @@ static int __init i2c_parport_device_add(u16 address)
|
||||||
goto exit;
|
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);
|
err = platform_device_add(pdev);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
|
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
|
||||||
|
@ -231,13 +203,16 @@ static int __init i2c_parport_init(void)
|
||||||
base = DEFAULT_BASE;
|
base = DEFAULT_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!request_region(base, 3, DRVNAME))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
if (!adapter_parm[type].getscl.val)
|
if (!adapter_parm[type].getscl.val)
|
||||||
parport_algo_data.getscl = NULL;
|
parport_algo_data.getscl = NULL;
|
||||||
|
|
||||||
/* Sets global pdev as a side effect */
|
/* Sets global pdev as a side effect */
|
||||||
err = i2c_parport_device_add(base);
|
err = i2c_parport_device_add(base);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit;
|
goto exit_release;
|
||||||
|
|
||||||
err = platform_driver_register(&i2c_parport_driver);
|
err = platform_driver_register(&i2c_parport_driver);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -247,7 +222,8 @@ static int __init i2c_parport_init(void)
|
||||||
|
|
||||||
exit_device:
|
exit_device:
|
||||||
platform_device_unregister(pdev);
|
platform_device_unregister(pdev);
|
||||||
exit:
|
exit_release:
|
||||||
|
release_region(base, 3);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +231,7 @@ static void __exit i2c_parport_exit(void)
|
||||||
{
|
{
|
||||||
platform_driver_unregister(&i2c_parport_driver);
|
platform_driver_unregister(&i2c_parport_driver);
|
||||||
platform_device_unregister(pdev);
|
platform_device_unregister(pdev);
|
||||||
|
release_region(base, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
#define DRIVER "i2c-pca-isa"
|
#define DRIVER "i2c-pca-isa"
|
||||||
#define IO_SIZE 4
|
#define IO_SIZE 4
|
||||||
|
|
||||||
static unsigned long base = 0x330;
|
static unsigned long base;
|
||||||
static int irq = 10;
|
static int irq = -1;
|
||||||
|
|
||||||
/* Data sheet recommends 59kHz for 100kHz operation due to variation
|
/* Data sheet recommends 59kHz for 100kHz operation due to variation
|
||||||
* in the actual clock rate */
|
* in the actual clock rate */
|
||||||
|
@ -107,6 +107,19 @@ static struct i2c_adapter pca_isa_ops = {
|
||||||
.timeout = 100,
|
.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)
|
static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
init_waitqueue_head(&pca_wait);
|
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);
|
i2c_del_adapter(&pca_isa_ops);
|
||||||
|
|
||||||
if (irq > 0) {
|
if (irq > -1) {
|
||||||
disable_irq(irq);
|
disable_irq(irq);
|
||||||
free_irq(irq, &pca_isa_ops);
|
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 = {
|
static struct isa_driver pca_isa_driver = {
|
||||||
|
.match = pca_isa_match,
|
||||||
.probe = pca_isa_probe,
|
.probe = pca_isa_probe,
|
||||||
.remove = __devexit_p(pca_isa_remove),
|
.remove = __devexit_p(pca_isa_remove),
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
VT8237S 0x3372 yes
|
VT8237S 0x3372 yes
|
||||||
VT8251 0x3287 yes
|
VT8251 0x3287 yes
|
||||||
CX700 0x8324 yes
|
CX700 0x8324 yes
|
||||||
|
VX800/VX820 0x8353 yes
|
||||||
|
|
||||||
Note: we assume there can only be one device, with one SMBus interface.
|
Note: we assume there can only be one device, with one SMBus interface.
|
||||||
*/
|
*/
|
||||||
|
@ -82,6 +83,7 @@ static unsigned short SMBHSTCFG = 0xD2;
|
||||||
#define VT596_BYTE 0x04
|
#define VT596_BYTE 0x04
|
||||||
#define VT596_BYTE_DATA 0x08
|
#define VT596_BYTE_DATA 0x08
|
||||||
#define VT596_WORD_DATA 0x0C
|
#define VT596_WORD_DATA 0x0C
|
||||||
|
#define VT596_PROC_CALL 0x10
|
||||||
#define VT596_BLOCK_DATA 0x14
|
#define VT596_BLOCK_DATA 0x14
|
||||||
#define VT596_I2C_BLOCK_DATA 0x34
|
#define VT596_I2C_BLOCK_DATA 0x34
|
||||||
|
|
||||||
|
@ -232,6 +234,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||||
}
|
}
|
||||||
size = VT596_WORD_DATA;
|
size = VT596_WORD_DATA;
|
||||||
break;
|
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:
|
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||||
if (!(vt596_features & FEATURE_I2CBLOCK))
|
if (!(vt596_features & FEATURE_I2CBLOCK))
|
||||||
goto exit_unsupported;
|
goto exit_unsupported;
|
||||||
|
@ -262,6 +270,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
if (size == VT596_PROC_CALL)
|
||||||
|
read_write = I2C_SMBUS_READ;
|
||||||
|
|
||||||
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
|
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -271,6 +282,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
||||||
data->byte = inb_p(SMBHSTDAT0);
|
data->byte = inb_p(SMBHSTDAT0);
|
||||||
break;
|
break;
|
||||||
case VT596_WORD_DATA:
|
case VT596_WORD_DATA:
|
||||||
|
case VT596_PROC_CALL:
|
||||||
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
|
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
|
||||||
break;
|
break;
|
||||||
case VT596_I2C_BLOCK_DATA:
|
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 |
|
u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||||
I2C_FUNC_SMBUS_BLOCK_DATA;
|
I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||||
|
|
||||||
if (vt596_features & FEATURE_I2CBLOCK)
|
if (vt596_features & FEATURE_I2CBLOCK)
|
||||||
func |= I2C_FUNC_SMBUS_I2C_BLOCK;
|
func |= I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||||
|
@ -396,6 +408,7 @@ found:
|
||||||
|
|
||||||
switch (pdev->device) {
|
switch (pdev->device) {
|
||||||
case PCI_DEVICE_ID_VIA_CX700:
|
case PCI_DEVICE_ID_VIA_CX700:
|
||||||
|
case PCI_DEVICE_ID_VIA_VX800:
|
||||||
case PCI_DEVICE_ID_VIA_8251:
|
case PCI_DEVICE_ID_VIA_8251:
|
||||||
case PCI_DEVICE_ID_VIA_8237:
|
case PCI_DEVICE_ID_VIA_8237:
|
||||||
case PCI_DEVICE_ID_VIA_8237A:
|
case PCI_DEVICE_ID_VIA_8237A:
|
||||||
|
@ -459,6 +472,8 @@ static struct pci_device_id vt596_ids[] = {
|
||||||
.driver_data = SMBBA3 },
|
.driver_data = SMBBA3 },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
|
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
|
||||||
.driver_data = SMBBA3 },
|
.driver_data = SMBBA3 },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
|
||||||
|
.driver_data = SMBBA3 },
|
||||||
{ 0, }
|
{ 0, }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,10 +49,9 @@ MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
struct isp1301 {
|
struct isp1301 {
|
||||||
struct otg_transceiver otg;
|
struct otg_transceiver otg;
|
||||||
struct i2c_client client;
|
struct i2c_client *client;
|
||||||
void (*i2c_release)(struct device *dev);
|
void (*i2c_release)(struct device *dev);
|
||||||
|
|
||||||
int irq;
|
|
||||||
int irq_type;
|
int irq_type;
|
||||||
|
|
||||||
u32 last_otg_ctrl;
|
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;
|
static struct i2c_driver isp1301_driver;
|
||||||
|
|
||||||
/* smbus apis are used for portability */
|
/* smbus apis are used for portability */
|
||||||
|
@ -153,25 +144,25 @@ static struct i2c_driver isp1301_driver;
|
||||||
static inline u8
|
static inline u8
|
||||||
isp1301_get_u8(struct isp1301 *isp, u8 reg)
|
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
|
static inline int
|
||||||
isp1301_get_u16(struct isp1301 *isp, u8 reg)
|
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
|
static inline int
|
||||||
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
|
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
|
static inline int
|
||||||
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
|
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;
|
int status;
|
||||||
|
|
||||||
if (isp && !test_and_set_bit(work, &isp->todo)) {
|
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);
|
status = schedule_work(&isp->work);
|
||||||
if (!status && !isp->working)
|
if (!status && !isp->working)
|
||||||
dev_vdbg(&isp->client.dev,
|
dev_vdbg(&isp->client->dev,
|
||||||
"work item %d may be lost\n", work);
|
"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 */
|
/* transfer state from otg engine to isp1301 */
|
||||||
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
|
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
|
||||||
otg_update_isp(isp);
|
otg_update_isp(isp);
|
||||||
put_device(&isp->client.dev);
|
put_device(&isp->client->dev);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* transfer state from isp1301 to otg engine */
|
/* transfer state from isp1301 to otg engine */
|
||||||
|
@ -1143,7 +1134,7 @@ isp1301_work(struct work_struct *work)
|
||||||
u8 stat = isp1301_clear_latch(isp);
|
u8 stat = isp1301_clear_latch(isp);
|
||||||
|
|
||||||
isp_update_otg(isp, stat);
|
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)) {
|
if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
|
||||||
|
@ -1178,7 +1169,7 @@ isp1301_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
host_resume(isp);
|
host_resume(isp);
|
||||||
// mdelay(10);
|
// mdelay(10);
|
||||||
put_device(&isp->client.dev);
|
put_device(&isp->client->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
|
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
|
||||||
|
@ -1187,15 +1178,15 @@ isp1301_work(struct work_struct *work)
|
||||||
if (!stop)
|
if (!stop)
|
||||||
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
|
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
|
||||||
#endif
|
#endif
|
||||||
put_device(&isp->client.dev);
|
put_device(&isp->client->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isp->todo)
|
if (isp->todo)
|
||||||
dev_vdbg(&isp->client.dev,
|
dev_vdbg(&isp->client->dev,
|
||||||
"work done, todo = 0x%lx\n",
|
"work done, todo = 0x%lx\n",
|
||||||
isp->todo);
|
isp->todo);
|
||||||
if (stop) {
|
if (stop) {
|
||||||
dev_dbg(&isp->client.dev, "stop\n");
|
dev_dbg(&isp->client->dev, "stop\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (isp->todo);
|
} while (isp->todo);
|
||||||
|
@ -1219,7 +1210,7 @@ static void isp1301_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct isp1301 *isp;
|
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() */
|
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
|
||||||
if (isp->i2c_release)
|
if (isp->i2c_release)
|
||||||
|
@ -1229,15 +1220,15 @@ static void isp1301_release(struct device *dev)
|
||||||
|
|
||||||
static struct isp1301 *the_transceiver;
|
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;
|
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_FALLING, ~0);
|
||||||
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
|
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
|
||||||
free_irq(isp->irq, isp);
|
free_irq(i2c->irq, isp);
|
||||||
#ifdef CONFIG_USB_OTG
|
#ifdef CONFIG_USB_OTG
|
||||||
otg_unbind(isp);
|
otg_unbind(isp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1252,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
|
||||||
put_device(&i2c->dev);
|
put_device(&i2c->dev);
|
||||||
the_transceiver = 0;
|
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,
|
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||||
INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1310,7 +1301,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
||||||
|
|
||||||
#ifdef CONFIG_USB_OTG
|
#ifdef CONFIG_USB_OTG
|
||||||
isp->otg.host = host;
|
isp->otg.host = host;
|
||||||
dev_dbg(&isp->client.dev, "registered host\n");
|
dev_dbg(&isp->client->dev, "registered host\n");
|
||||||
host_suspend(isp);
|
host_suspend(isp);
|
||||||
if (isp->otg.gadget)
|
if (isp->otg.gadget)
|
||||||
return isp1301_otg_enable(isp);
|
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())
|
if (machine_is_omap_h2())
|
||||||
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
|
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,
|
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
|
||||||
INTR_ID_GND);
|
INTR_ID_GND);
|
||||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||||
|
@ -1343,7 +1334,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
dev_dbg(&isp->client.dev, "host sessions not allowed\n");
|
dev_dbg(&isp->client->dev, "host sessions not allowed\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1370,7 +1361,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
||||||
|
|
||||||
#ifdef CONFIG_USB_OTG
|
#ifdef CONFIG_USB_OTG
|
||||||
isp->otg.gadget = gadget;
|
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 () */
|
/* gadget driver may be suspended until vbus_connect () */
|
||||||
if (isp->otg.host)
|
if (isp->otg.host)
|
||||||
return isp1301_otg_enable(isp);
|
return isp1301_otg_enable(isp);
|
||||||
|
@ -1395,7 +1386,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
|
||||||
INTR_SESS_VLD);
|
INTR_SESS_VLD);
|
||||||
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
|
||||||
INTR_VBUS_VLD);
|
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__);
|
dump_regs(isp, __func__);
|
||||||
|
|
||||||
/* If this has a Mini-AB connector, this mode is highly
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
|
dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1508,12 +1499,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* no error returns, they'd just make bus scanning stop */
|
static int __init isp1301_probe(struct i2c_client *i2c)
|
||||||
static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
|
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
struct isp1301 *isp;
|
struct isp1301 *isp;
|
||||||
struct i2c_client *i2c;
|
|
||||||
|
|
||||||
if (the_transceiver)
|
if (the_transceiver)
|
||||||
return 0;
|
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.function = isp1301_timer;
|
||||||
isp->timer.data = (unsigned long) isp;
|
isp->timer.data = (unsigned long) isp;
|
||||||
|
|
||||||
isp->irq = -1;
|
i2c_set_clientdata(i2c, isp);
|
||||||
isp->client.addr = address;
|
isp->client = i2c;
|
||||||
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;
|
|
||||||
|
|
||||||
/* if this is a true probe, verify the chip ... */
|
/* verify the chip (shouldn't be necesary) */
|
||||||
if (kind < 0) {
|
status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
|
||||||
status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
|
if (status != I2C_VENDOR_ID_PHILIPS) {
|
||||||
if (status != I2C_VENDOR_ID_PHILIPS) {
|
dev_dbg(&i2c->dev, "not philips id: %d\n", status);
|
||||||
dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
|
goto fail;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
|
||||||
status = i2c_attach_client(i2c);
|
if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
|
||||||
if (status < 0) {
|
dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
|
||||||
dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
|
goto fail;
|
||||||
DRIVER_NAME, address, status);
|
|
||||||
fail1:
|
|
||||||
kfree(isp);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
isp->i2c_release = i2c->dev.release;
|
isp->i2c_release = i2c->dev.release;
|
||||||
i2c->dev.release = isp1301_release;
|
i2c->dev.release = isp1301_release;
|
||||||
|
@ -1586,7 +1557,7 @@ fail1:
|
||||||
status = otg_bind(isp);
|
status = otg_bind(isp);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
dev_dbg(&i2c->dev, "can't bind OTG\n");
|
dev_dbg(&i2c->dev, "can't bind OTG\n");
|
||||||
goto fail2;
|
goto fail;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1599,26 +1570,21 @@ fail1:
|
||||||
|
|
||||||
/* IRQ wired at M14 */
|
/* IRQ wired at M14 */
|
||||||
omap_cfg_reg(M14_1510_GPIO2);
|
omap_cfg_reg(M14_1510_GPIO2);
|
||||||
isp->irq = OMAP_GPIO_IRQ(2);
|
|
||||||
if (gpio_request(2, "isp1301") == 0)
|
if (gpio_request(2, "isp1301") == 0)
|
||||||
gpio_direction_input(2);
|
gpio_direction_input(2);
|
||||||
isp->irq_type = IRQF_TRIGGER_FALLING;
|
isp->irq_type = IRQF_TRIGGER_FALLING;
|
||||||
}
|
}
|
||||||
|
|
||||||
isp->irq_type |= IRQF_SAMPLE_RANDOM;
|
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);
|
isp->irq_type, DRIVER_NAME, isp);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
|
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
|
||||||
isp->irq, status);
|
i2c->irq, status);
|
||||||
#ifdef CONFIG_USB_OTG
|
goto fail;
|
||||||
fail2:
|
|
||||||
#endif
|
|
||||||
i2c_detach_client(i2c);
|
|
||||||
goto fail1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isp->otg.dev = &isp->client.dev;
|
isp->otg.dev = &i2c->dev;
|
||||||
isp->otg.label = DRIVER_NAME;
|
isp->otg.label = DRIVER_NAME;
|
||||||
|
|
||||||
isp->otg.set_host = isp1301_set_host,
|
isp->otg.set_host = isp1301_set_host,
|
||||||
|
@ -1649,22 +1615,25 @@ fail2:
|
||||||
status);
|
status);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
kfree(isp);
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isp1301_scan_bus(struct i2c_adapter *bus)
|
static const struct i2c_device_id isp1301_id[] = {
|
||||||
{
|
{ "isp1301_omap", 0 },
|
||||||
if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
|
{ }
|
||||||
| I2C_FUNC_SMBUS_READ_WORD_DATA))
|
};
|
||||||
return -EINVAL;
|
MODULE_DEVICE_TABLE(i2c, isp1301_id);
|
||||||
return i2c_probe(bus, &addr_data, isp1301_probe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct i2c_driver isp1301_driver = {
|
static struct i2c_driver isp1301_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "isp1301_omap",
|
.name = "isp1301_omap",
|
||||||
},
|
},
|
||||||
.attach_adapter = isp1301_scan_bus,
|
.probe = isp1301_probe,
|
||||||
.detach_client = isp1301_detach_client,
|
.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 0..3 == GPIO1..GPIO4
|
||||||
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
|
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
|
||||||
|
* offset 6 == vibrator motor driver
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
{
|
{
|
||||||
if (offset < 4)
|
if (offset < 4)
|
||||||
tps65010_set_gpio_out_value(offset + 1, value);
|
tps65010_set_gpio_out_value(offset + 1, value);
|
||||||
else
|
else if (offset < 6)
|
||||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||||
|
else
|
||||||
|
tps65010_set_vib(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -477,8 +480,10 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
if (!(tps->outmask & (1 << offset)))
|
if (!(tps->outmask & (1 << offset)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tps65010_set_gpio_out_value(offset + 1, value);
|
tps65010_set_gpio_out_value(offset + 1, value);
|
||||||
} else
|
} else if (offset < 6)
|
||||||
tps65010_set_led(offset - 3, value ? ON : OFF);
|
tps65010_set_led(offset - 3, value ? ON : OFF);
|
||||||
|
else
|
||||||
|
tps65010_set_vib(value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -646,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
|
||||||
tps->chip.get = tps65010_gpio_get;
|
tps->chip.get = tps65010_gpio_get;
|
||||||
|
|
||||||
tps->chip.base = board->base;
|
tps->chip.base = board->base;
|
||||||
tps->chip.ngpio = 6;
|
tps->chip.ngpio = 7;
|
||||||
tps->chip.can_sleep = 1;
|
tps->chip.can_sleep = 1;
|
||||||
|
|
||||||
status = gpiochip_add(&tps->chip);
|
status = gpiochip_add(&tps->chip);
|
||||||
|
@ -675,6 +680,7 @@ static const struct i2c_device_id tps65010_id[] = {
|
||||||
{ "tps65011", TPS65011 },
|
{ "tps65011", TPS65011 },
|
||||||
{ "tps65012", TPS65012 },
|
{ "tps65012", TPS65012 },
|
||||||
{ "tps65013", TPS65013 },
|
{ "tps65013", TPS65013 },
|
||||||
|
{ "tps65014", TPS65011 }, /* tps65011 charging at 6.5V max */
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, tps65010_id);
|
MODULE_DEVICE_TABLE(i2c, tps65010_id);
|
||||||
|
|
|
@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
int res = 0, dummy;
|
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->bus_lock);
|
||||||
mutex_init(&adap->clist_lock);
|
mutex_init(&adap->clist_lock);
|
||||||
INIT_LIST_HEAD(&adap->clients);
|
INIT_LIST_HEAD(&adap->clients);
|
||||||
|
@ -696,6 +700,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
|
||||||
{
|
{
|
||||||
int res;
|
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 */
|
/* new style driver methods can't mix with legacy ones */
|
||||||
if (is_newstyle_driver(driver)) {
|
if (is_newstyle_driver(driver)) {
|
||||||
if (driver->attach_adapter || driver->detach_adapter
|
if (driver->attach_adapter || driver->detach_adapter
|
||||||
|
@ -978,7 +986,10 @@ static void __exit i2c_exit(void)
|
||||||
bus_unregister(&i2c_bus_type);
|
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);
|
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);
|
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
|
* i2c_smbus_read_block_data - SMBus "block read" protocol
|
||||||
* @client: Handle to slave device
|
* @client: Handle to slave device
|
||||||
|
|
Загрузка…
Ссылка в новой задаче