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