9
0
Fork 0

Merge branch 'for-next/i2c' into for-next/at91

This commit is contained in:
Sascha Hauer 2012-11-15 20:20:19 +01:00
commit 18f044436e
26 changed files with 1972 additions and 34 deletions

View File

@ -47,6 +47,7 @@ mem_initcall(vpb_mem_init);
static int vpb_devices_init(void)
{
add_cfi_flash_device(DEVICE_ID_DYNAMIC, VERSATILE_FLASH_BASE, VERSATILE_FLASH_SIZE, 0);
versatile_register_i2c();
devfs_add_partition("nor0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self");
devfs_add_partition("nor0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env0");

View File

@ -33,6 +33,7 @@ CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y
CONFIG_NET=y
CONFIG_NET_DHCP=y
CONFIG_NET_NFS=y
@ -43,6 +44,8 @@ CONFIG_NET_NETCONSOLE=y
CONFIG_NET_RESOLV=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_DRIVER_NET_SMC91111=y
CONFIG_I2C=y
CONFIG_I2C_VERSATILE=y
CONFIG_FS_CRAMFS=y
CONFIG_SHA1=y
CONFIG_SHA256=y

View File

@ -26,6 +26,7 @@
#include <init.h>
#include <clock.h>
#include <debug_ll.h>
#include <sizes.h>
#include <linux/clkdev.h>
#include <linux/clk.h>
@ -182,6 +183,12 @@ void versatile_register_uart(unsigned id)
amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
}
void versatile_register_i2c(void)
{
add_generic_device("versatile-i2c", DEVICE_ID_DYNAMIC, NULL,
VERSATILE_I2C_BASE, SZ_4K, IORESOURCE_MEM, NULL);
}
void __noreturn reset_cpu (unsigned long ignored)
{
u32 val;

View File

@ -4,5 +4,6 @@
void versatile_add_sdram(u32 size);
void versatile_register_uart(unsigned id);
void versatile_register_i2c(void);
#endif

View File

@ -8,4 +8,23 @@ config EEPROM_AT25
after you configure the board init code to know about each eeprom
on your target board.
config EEPROM_AT24
bool "at24 based eeprom"
depends on I2C
help
Enable this driver to get read/write support to most I2C EEPROMs,
after you configure the driver to know about each EEPROM on
your target board. Use these generic chip names, instead of
vendor-specific ones like at24c64 or 24lc02:
24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
Unless you like data loss puzzles, always be sure that any chip
you configure as a 24c32 (32 kbit) or larger is NOT really a
24c16 (16 kbit) or smaller, and vice versa. Marking the chip
as read-only won't help recover from this. Also, if your chip
has any software write-protect mechanism you may want to review the
code to make sure this driver won't turn it on by accident.
endmenu

View File

@ -1 +1,2 @@
obj-$(CONFIG_EEPROM_AT25) += at25.o
obj-$(CONFIG_EEPROM_AT24) += at24.o

460
drivers/eeprom/at24.c Normal file
View File

@ -0,0 +1,460 @@
/*
* at24.c - handle most I2C EEPROMs
*
* Copyright (C) 2005-2007 David Brownell
* Copyright (C) 2008 Wolfram Sang, Pengutronix
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <common.h>
#include <init.h>
#include <malloc.h>
#include <clock.h>
#include <driver.h>
#include <xfuncs.h>
#include <errno.h>
#include <linux/math64.h>
#include <linux/log2.h>
#include <i2c/i2c.h>
#include <i2c/at24.h>
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
* Differences between different vendor product lines (like Atmel AT24C or
* MicroChip 24LC, etc) won't much matter for typical read/write access.
* There are also I2C RAM chips, likewise interchangeable. One example
* would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
*
* However, misconfiguration can lose data. "Set 16-bit memory address"
* to a part with 8-bit addressing will overwrite data. Writing with too
* big a page size also loses data. And it's not safe to assume that the
* conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
* uses 0x51, for just one example.
*
* So this driver uses "new style" I2C driver binding, expecting to be
* told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
* similar kernel-resident tables; or, configuration data coming from
* a bootloader.
*
* Other than binding model, current differences from "eeprom" driver are
* that this one handles write access and isn't restricted to 24c02 devices.
* It also handles larger devices (32 kbit and up) with two-byte addresses,
* which won't work on pure SMBus systems.
*/
struct at24_data {
struct at24_platform_data chip;
struct cdev cdev;
struct file_operations fops;
u8 *writebuf;
unsigned write_max;
unsigned num_addresses;
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us.
*/
struct i2c_client *client[];
};
/*
* This parameter is to help this driver avoid blocking other drivers out
* of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
* clock, one 256 byte read takes about 1/43 second which is excessive;
* but the 1/170 second it takes at 400 kHz may be quite reasonable; and
* at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
*
* This value is forced to be a power of two so that writes align on pages.
*/
static unsigned io_limit = 128;
/*
* Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts.
*/
static unsigned write_timeout = 25;
#define AT24_SIZE_BYTELEN 5
#define AT24_SIZE_FLAGS 8
#define AT24_BITMASK(x) (BIT(x) - 1)
/* create non-zero magic value for given eeprom parameters */
#define AT24_DEVICE_MAGIC(_len, _flags) \
((1 << AT24_SIZE_FLAGS | (_flags)) \
<< AT24_SIZE_BYTELEN | ilog2(_len))
static struct platform_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
/* spd is a 24c02 in memory DIMMs */
{ "spd", AT24_DEVICE_MAGIC(2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
/* 24rf08 quirk is handled at i2c-core */
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
/*-------------------------------------------------------------------------*/
/*
* This routine supports chips which consume multiple I2C addresses. It
* computes the addressing information to be used for a given r/w request.
* Assumes that sanity checks for offset happened at sysfs-layer.
*/
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
unsigned *offset)
{
unsigned i;
if (at24->chip.flags & AT24_FLAG_ADDR16) {
i = *offset >> 16;
*offset &= 0xffff;
} else {
i = *offset >> 8;
*offset &= 0xff;
}
return at24->client[i];
}
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
unsigned offset, size_t count)
{
struct i2c_msg msg[2];
u8 msgbuf[2];
struct i2c_client *client;
int status, i;
uint64_t start, read_time;
memset(msg, 0, sizeof(msg));
/*
* REVISIT some multi-address chips don't rollover page reads to
* the next slave address, so we may need to truncate the count.
* Those chips might need another quirk flag.
*
* If the real hardware used four adjacent 24c02 chips and that
* were misconfigured as one 24c08, that would be a similar effect:
* one "eeprom" file not four, but larger reads would fail when
* they crossed certain pages.
*/
/*
* Slave address and byte offset derive from the offset. Always
* set the byte address; on a multi-master board, another master
* may have changed the chip's "current" address pointer.
*/
client = at24_translate_offset(at24, &offset);
if (count > io_limit)
count = io_limit;
i = 0;
if (at24->chip.flags & AT24_FLAG_ADDR16)
msgbuf[i++] = offset >> 8;
msgbuf[i++] = offset;
msg[0].addr = client->addr;
msg[0].buf = msgbuf;
msg[0].len = i;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
/*
* Reads fail if the previous write didn't complete yet. We may
* loop a few times until this one succeeds, waiting at least
* long enough for one entire page write to work.
*/
start = get_time_ns();
do {
read_time = get_time_ns();
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
status = count;
dev_dbg(&client->dev, "read %zu@%d --> %d (%llu)\n",
count, offset, status, read_time);
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
mdelay(1);
} while (!is_timeout(start, write_timeout * MSECOND));
return -ETIMEDOUT;
}
static ssize_t at24_read(struct at24_data *at24,
char *buf, loff_t off, size_t count)
{
ssize_t retval = 0;
if (unlikely(!count))
return count;
/*
* Read data from chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
*/
while (count) {
ssize_t status;
status = at24_eeprom_read(at24, buf, off, count);
if (status <= 0) {
if (retval == 0)
retval = status;
break;
}
buf += status;
off += status;
count -= status;
retval += status;
}
return retval;
}
static ssize_t at24_cdev_read(struct cdev *cdev, void *buf, size_t count,
loff_t off, ulong flags)
{
struct at24_data *at24 = cdev->priv;
return at24_read(at24, buf, off, count);
}
/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
* variants here, including OTP fuses and partial chip protect.
*
* We only use page mode writes; the alternative is sloooow. This routine
* writes at most one page.
*/
static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
unsigned offset, size_t count)
{
struct i2c_client *client;
struct i2c_msg msg;
ssize_t status;
uint64_t start, write_time;
unsigned next_page;
int i = 0;
/* Get corresponding I2C address and adjust offset */
client = at24_translate_offset(at24, &offset);
/* write_max is at most a page */
if (count > at24->write_max)
count = at24->write_max;
/* Never roll over backwards, to the start of this page */
next_page = roundup(offset + 1, at24->chip.page_size);
if (offset + count > next_page)
count = next_page - offset;
msg.addr = client->addr;
msg.flags = 0;
/* msg.buf is u8 and casts will mask the values */
msg.buf = at24->writebuf;
if (at24->chip.flags & AT24_FLAG_ADDR16)
msg.buf[i++] = offset >> 8;
msg.buf[i++] = offset;
memcpy(&msg.buf[i], buf, count);
msg.len = i + count;
/*
* Writes fail if the previous one didn't complete yet. We may
* loop a few times until this one succeeds, waiting at least
* long enough for one entire page write to work.
*/
start = get_time_ns();
do {
write_time = get_time_ns();
status = i2c_transfer(client->adapter, &msg, 1);
if (status == 1)
status = count;
dev_dbg(&client->dev, "write %zu@%d --> %zd (%llu)\n",
count, offset, status, write_time);
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
mdelay(1);
} while (!is_timeout(start, write_timeout * MSECOND));
return -ETIMEDOUT;
}
static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
size_t count)
{
ssize_t retval = 0;
if (unlikely(!count))
return count;
while (count) {
ssize_t status;
status = at24_eeprom_write(at24, buf, off, count);
if (status <= 0) {
if (retval == 0)
retval = status;
break;
}
buf += status;
off += status;
count -= status;
retval += status;
}
return retval;
}
static ssize_t at24_cdev_write(struct cdev *cdev, const void *buf, size_t count,
loff_t off, ulong flags)
{
struct at24_data *at24 = cdev->priv;
return at24_write(at24, buf, off, count);
}
static int at24_probe(struct device_d *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct at24_platform_data chip;
bool writable;
struct at24_data *at24;
int err;
unsigned i, num_addresses;
if (dev->platform_data) {
chip = *(struct at24_platform_data *)dev->platform_data;
} else {
unsigned long magic;
err = dev_get_drvdata(dev, (unsigned long *)&magic);
if (err)
return err;
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
magic >>= AT24_SIZE_BYTELEN;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
chip.page_size = 1;
}
if (!is_power_of_2(chip.byte_len))
dev_warn(&client->dev,
"byte_len looks suspicious (no power of 2)!\n");
if (!chip.page_size) {
dev_err(&client->dev, "page_size must not be 0!\n");
err = -EINVAL;
goto err_out;
}
if (!is_power_of_2(chip.page_size))
dev_warn(&client->dev,
"page_size looks suspicious (no power of 2)!\n");
if (chip.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8;
else
num_addresses = DIV_ROUND_UP(chip.byte_len,
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
at24 = xzalloc(sizeof(struct at24_data) +
num_addresses * sizeof(struct i2c_client *));
at24->chip = chip;
at24->num_addresses = num_addresses;
at24->cdev.name = asprintf("eeprom%d", dev->id);
at24->cdev.priv = at24;
at24->cdev.dev = dev;
at24->cdev.ops = &at24->fops;
at24->fops.lseek = dev_lseek_default;
at24->fops.read = at24_cdev_read,
at24->cdev.size = chip.byte_len;
writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
unsigned write_max = chip.page_size;
at24->fops.write = at24_cdev_write;
if (write_max > io_limit)
write_max = io_limit;
at24->write_max = write_max;
/* buffer (data + address at the beginning) */
at24->writebuf = xmalloc(write_max + 2);
}
at24->client[0] = client;
/* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) {
at24->client[i] = i2c_new_dummy(client->adapter,
client->addr + i);
if (!at24->client[i]) {
dev_err(&client->dev, "address 0x%02x unavailable\n",
client->addr + i);
err = -EADDRINUSE;
goto err_clients;
}
}
devfs_create(&at24->cdev);
return 0;
err_clients:
kfree(at24->writebuf);
kfree(at24);
err_out:
dev_dbg(&client->dev, "probe error %d\n", err);
return err;
}
static struct driver_d at24_driver = {
.name = "at24",
.probe = at24_probe,
.id_table = at24_ids,
};
static int at24_init(void)
{
i2c_register_driver(&at24_driver);
return 0;
}
device_initcall(at24_init);

View File

@ -3,6 +3,7 @@ menuconfig I2C
if I2C
source drivers/i2c/algos/Kconfig
source drivers/i2c/busses/Kconfig
endif

View File

@ -1 +1 @@
obj-$(CONFIG_I2C) += i2c.o busses/
obj-$(CONFIG_I2C) += i2c.o busses/ algos/

View File

@ -0,0 +1,6 @@
#
# I2C algorithm drivers configuration
#
config I2C_ALGOBIT
bool

View File

@ -0,0 +1,5 @@
#
# Makefile for the i2c algorithms
#
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o

View File

@ -0,0 +1,605 @@
/* -------------------------------------------------------------------------
* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
* -------------------------------------------------------------------------
* Copyright (C) 1995-2000 Simon G. Vogl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
* ------------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
#include <common.h>
#include <init.h>
#include <errno.h>
#include <clock.h>
#include <i2c/i2c.h>
#include <i2c/i2c-algo-bit.h>
/* ----- global defines ----------------------------------------------- */
#ifdef DEBUG
#define bit_dbg(level, dev, format, args...) \
do { \
if (i2c_debug >= level) \
dev_dbg(dev, format, ##args); \
} while (0)
#else
#define bit_dbg(level, dev, format, args...) \
do {} while (0)
#endif /* DEBUG */
/* ----- global variables --------------------------------------------- */
static int bit_test; /* see if the line-setting functions work */
#ifdef DEBUG
static int i2c_debug = 1;
#endif
/* --- setting states on the bus with the right timing: --------------- */
#define setsda(adap, val) adap->setsda(adap->data, val)
#define setscl(adap, val) adap->setscl(adap->data, val)
#define getsda(adap) adap->getsda(adap->data)
#define getscl(adap) adap->getscl(adap->data)
static inline void sdalo(struct i2c_algo_bit_data *adap)
{
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
}
static inline void sdahi(struct i2c_algo_bit_data *adap)
{
setsda(adap, 1);
udelay((adap->udelay + 1) / 2);
}
static inline void scllo(struct i2c_algo_bit_data *adap)
{
setscl(adap, 0);
udelay(adap->udelay / 2);
}
/*
* Raise scl line, and do checking for delays. This is necessary for slower
* devices.
*/
static int sclhi(struct i2c_algo_bit_data *adap)
{
uint64_t start;
setscl(adap, 1);
/* Not all adapters have scl sense line... */
if (!adap->getscl)
goto done;
start = get_time_ns();
while (!getscl(adap)) {
/* This hw knows how to read the clock line, so we wait
* until it actually gets high. This is safer as some
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
if (is_timeout(start, adap->timeout_ms * MSECOND)) {
/* Test one last time, as we may have been preempted
* between last check and timeout test.
*/
if (getscl(adap))
break;
return -ETIMEDOUT;
}
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
"high\n", jiffies - start);
#endif
done:
udelay(adap->udelay);
return 0;
}
/* --- other auxiliary functions -------------------------------------- */
static void i2c_start(struct i2c_algo_bit_data *adap)
{
/* assert: scl, sda are high */
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_repstart(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdahi(adap);
sclhi(adap);
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_stop(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdalo(adap);
sclhi(adap);
setsda(adap, 1);
udelay(adap->udelay);
}
/* send a byte without start cond., look for arbitration,
check ackn. from slave */
/* returns:
* 1 if the device acknowledged
* 0 if the device did not ack
* -ETIMEDOUT if an error occurred (while raising the scl line)
*/
static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
{
int i;
int sb;
int ack;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
for (i = 7; i >= 0; i--) {
sb = (c >> i) & 1;
setsda(adap, sb);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
"timeout at bit #%d\n", (int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
* if (sb && !getsda(adap)) -> ouch! Get out of here.
*
* Report a unique code, so higher level code can retry
* the whole (combined) message and *NOT* issue STOP.
*/
scllo(adap);
}
sdahi(adap);
if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
"timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
*/
ack = !getsda(adap); /* ack: sda is pulled low -> success */
bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
ack ? "A" : "NA");
scllo(adap);
return ack;
/* assert: scl is low (sda undef) */
}
static int i2c_inb(struct i2c_adapter *i2c_adap)
{
/* read byte via i2c port, without start/stop sequence */
/* acknowledge is sent in i2c_read. */
int i;
unsigned char indata = 0;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
sdahi(adap);
for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
"#%d\n", 7 - i);
return -ETIMEDOUT;
}
indata *= 2;
if (getsda(adap))
indata |= 0x01;
setscl(adap, 0);
udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
}
/* assert: scl is low */
return indata;
}
/*
* Sanity check for the adapter hardware - check the reaction of
* the bus lines only if it seems to be idle.
*/
static int test_bus(struct i2c_adapter *i2c_adap)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
struct device_d *dev = &i2c_adap->dev;
int scl, sda, ret;
if (adap->pre_xfer) {
ret = adap->pre_xfer(i2c_adap);
if (ret < 0)
return -ENODEV;
}
if (adap->getscl == NULL)
dev_info(dev, "Testing SDA only, SCL is not readable\n");
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!scl || !sda) {
dev_warn(dev, "bus seems to be busy (scl=%d, sda=%d)\n", scl, sda);
goto bailout;
}
sdalo(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (sda) {
dev_warn(dev, "SDA stuck high!\n");
goto bailout;
}
if (!scl) {
dev_warn(dev, "SCL unexpected low while pulling SDA low!\n");
goto bailout;
}
sdahi(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!sda) {
dev_warn(dev, "SDA stuck low!\n");
goto bailout;
}
if (!scl) {
dev_warn(dev, "SCL unexpected low while pulling SDA high!\n");
goto bailout;
}
scllo(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 0 : getscl(adap);
if (scl) {
dev_warn(dev, "SCL stuck high!\n");
goto bailout;
}
if (!sda) {
dev_warn(dev, "SDA unexpected low while pulling SCL low!\n");
goto bailout;
}
sclhi(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!scl) {
dev_warn(dev, "SCL stuck low!\n");
goto bailout;
}
if (!sda) {
dev_warn(dev, "SDA unexpected low while pulling SCL high!\n");
goto bailout;
}
if (adap->post_xfer)
adap->post_xfer(i2c_adap);
dev_info(dev, "Test OK\n");
return 0;
bailout:
sdahi(adap);
sclhi(adap);
if (adap->post_xfer)
adap->post_xfer(i2c_adap);
return -ENODEV;
}
/* ----- Utility functions
*/
/* try_address tries to contact a chip for a number of
* times before it gives up.
* return values:
* 1 chip answered
* 0 chip did not answer
* -x transmission error
*/
static int try_address(struct i2c_adapter *i2c_adap,
unsigned char addr, int retries)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret = 0;
for (i = 0; i <= retries; i++) {
ret = i2c_outb(i2c_adap, addr);
if (ret == 1 || i == retries)
break;
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
udelay(adap->udelay);
bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
}
if (i && ret)
bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
"0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?");
return ret;
}
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
const unsigned char *temp = msg->buf;
int count = msg->len;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
int retval;
int wrcount = 0;
while (count > 0) {
retval = i2c_outb(i2c_adap, *temp);
/* OK/ACK; or ignored NAK */
if ((retval > 0) || (nak_ok && (retval == 0))) {
count--;
temp++;
wrcount++;
/* A slave NAKing the master means the slave didn't like
* something about the data it saw. For example, maybe
* the SMBus PEC was wrong.
*/
} else if (retval == 0) {
dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
return -EIO;
/* Timeout; or (someday) lost arbitration
*
* FIXME Lost ARB implies retrying the transaction from
* the first message, after the "winning" master issues
* its STOP. As a rule, upper layer code has no reason
* to know or care about this ... it is *NOT* an error.
*/
} else {
dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
retval);
return retval;
}
}
return wrcount;
}
static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: sda is high */
if (is_ack) /* send ack */
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timeout */
dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
return -ETIMEDOUT;
}
scllo(adap);
return 0;
}
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount = 0; /* counts bytes read */
unsigned char *temp = msg->buf;
int count = msg->len;
while (count > 0) {
inval = i2c_inb(i2c_adap);
if (inval >= 0) {
*temp = inval;
rdcount++;
} else { /* read timed out */
break;
}
temp++;
count--;
bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
inval,
(flags & I2C_M_NO_RD_ACK)
? "(no ack/nak)"
: (count ? "A" : "NA"));
inval = acknak(i2c_adap, count);
if (inval < 0)
return inval;
}
return rdcount;
}
/* doAddress initiates the transfer by generating the start condition (in
* try_address) and transmits the address in the necessary format to handle
* reads, writes as well as 10bit-addresses.
* returns:
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
* -x an error occurred (like: -ENXIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
unsigned char addr;
int ret, retries;
retries = nak_ok ? 0 : i2c_adap->retries;
if (flags & I2C_M_TEN) {
/* a ten bit address */
addr = 0xf0 | ((msg->addr >> 7) & 0x06);
bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
/* try extended address code...*/
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
dev_err(&i2c_adap->dev,
"died at extended address code\n");
return -ENXIO;
}
/* the remaining 8 bit address */
ret = i2c_outb(i2c_adap, msg->addr & 0xff);
if ((ret != 1) && !nak_ok) {
/* the chip did not ack / xmission error occurred */
dev_err(&i2c_adap->dev, "died at 2nd address code\n");
return -ENXIO;
}
if (flags & I2C_M_RD) {
bit_dbg(3, &i2c_adap->dev, "emitting repeated "
"start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
dev_err(&i2c_adap->dev,
"died at repeated address code\n");
return -EIO;
}
}
} else { /* normal 7bit address */
addr = msg->addr << 1;
if (flags & I2C_M_RD)
addr |= 1;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok)
return -ENXIO;
}
return 0;
}
static int bit_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct i2c_msg *pmsg;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret;
unsigned short nak_ok;
if (adap->pre_xfer) {
ret = adap->pre_xfer(i2c_adap);
if (ret < 0)
return ret;
}
bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (i) {
bit_dbg(3, &i2c_adap->dev, "emitting "
"repeated start condition\n");
i2c_repstart(adap);
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
bit_dbg(1, &i2c_adap->dev, "NAK from "
"device addr 0x%02x msg #%d\n",
msgs[i].addr, i);
goto bailout;
}
if (pmsg->flags & I2C_M_RD) {
/* read bytes into buffer*/
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
} else {
/* write bytes from buffer */
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
}
}
ret = i;
bailout:
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
if (adap->post_xfer)
adap->post_xfer(i2c_adap);
return ret;
}
/*
* registering functions to load algorithms at runtime
*/
static int __i2c_bit_add_bus(struct i2c_adapter *adap,
int (*add_adapter)(struct i2c_adapter *))
{
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
int ret;
if (bit_test) {
ret = test_bus(adap);
if (bit_test >= 2 && ret < 0)
return -ENODEV;
}
/* register new adapter to i2c module... */
//adap->algo = &i2c_bit_algo;
adap->retries = 3;
adap->master_xfer = bit_xfer;
ret = add_adapter(adap);
if (ret < 0)
return ret;
/* Complain if SCL can't be read */
if (bit_adap->getscl == NULL) {
dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
dev_warn(&adap->dev, "Bus may be unreliable\n");
}
return 0;
}
int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{
return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}
EXPORT_SYMBOL(i2c_bit_add_numbered_bus);

View File

@ -4,6 +4,14 @@
menu "I2C Hardware Bus support"
config I2C_GPIO
tristate "GPIO-based bitbanging I2C"
depends on GENERIC_GPIO
select I2C_ALGOBIT
help
This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines.
config I2C_IMX
bool "MPC85xx/i.MX I2C Master driver"
depends on (ARCH_IMX && !ARCH_IMX1) || ARCH_MPC85XX
@ -12,4 +20,12 @@ config I2C_OMAP
bool "OMAP I2C Master driver"
depends on ARCH_OMAP
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
depends on ARCH_VERSATILE
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
range of platforms.
endmenu

View File

@ -1,2 +1,4 @@
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o

View File

@ -0,0 +1,177 @@
/*
* Bitbanging I2C bus driver using the GPIO API
*
* Copyright (C) 2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <common.h>
#include <driver.h>
#include <i2c/i2c.h>
#include <i2c/i2c-algo-bit.h>
#include <i2c/i2c-gpio.h>
#include <init.h>
#include <gpio.h>
struct i2c_gpio_private_data {
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
};
/* Toggle SDA by changing the direction of the pin */
static void i2c_gpio_setsda_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->sda_pin);
else
gpio_direction_output(pdata->sda_pin, 0);
}
/*
* Toggle SDA by changing the output value of the pin. This is only
* valid for pins configured as open drain (i.e. setting the value
* high effectively turns off the output driver.)
*/
static void i2c_gpio_setsda_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_set_value(pdata->sda_pin, state);
}
/* Toggle SCL by changing the direction of the pin. */
static void i2c_gpio_setscl_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->scl_pin);
else
gpio_direction_output(pdata->scl_pin, 0);
}
/*
* Toggle SCL by changing the output value of the pin. This is used
* for pins that are configured as open drain and for output-only
* pins. The latter case will break the i2c protocol, but it will
* often work in practice.
*/
static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_set_value(pdata->scl_pin, state);
}
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
return gpio_get_value(pdata->sda_pin);
}
static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
return gpio_get_value(pdata->scl_pin);
}
static int i2c_gpio_probe(struct device_d *dev)
{
struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
int ret;
priv = xzalloc(sizeof(*priv));
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
if (!dev->platform_data)
return -ENXIO;
memcpy(pdata, dev->platform_data, sizeof(*pdata));
ret = gpio_request(pdata->sda_pin, "sda");
if (ret)
goto err_request_sda;
ret = gpio_request(pdata->scl_pin, "scl");
if (ret)
goto err_request_scl;
if (pdata->sda_is_open_drain) {
gpio_direction_output(pdata->sda_pin, 1);
bit_data->setsda = i2c_gpio_setsda_val;
} else {
gpio_direction_input(pdata->sda_pin);
bit_data->setsda = i2c_gpio_setsda_dir;
}
if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
gpio_direction_output(pdata->scl_pin, 1);
bit_data->setscl = i2c_gpio_setscl_val;
} else {
gpio_direction_input(pdata->scl_pin);
bit_data->setscl = i2c_gpio_setscl_dir;
}
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
else if (pdata->scl_is_output_only)
bit_data->udelay = 50; /* 10 kHz */
else
bit_data->udelay = 5; /* 100 kHz */
if (pdata->timeout_ms)
bit_data->timeout_ms = pdata->timeout_ms;
else
bit_data->timeout_ms = 100; /* 100 ms */
bit_data->data = pdata;
adap->algo_data = bit_data;
adap->dev.parent = dev;
adap->nr = dev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
goto err_add_bus;
dev_info(dev, "using pins %u (SDA) and %u (SCL%s)\n",
pdata->sda_pin, pdata->scl_pin,
pdata->scl_is_output_only
? ", no clock stretching" : "");
return 0;
err_add_bus:
gpio_free(pdata->scl_pin);
err_request_scl:
gpio_free(pdata->sda_pin);
err_request_sda:
return ret;
}
static struct driver_d i2c_gpio_driver = {
.name = "i2c-gpio",
.probe = i2c_gpio_probe,
};
static int __init i2c_gpio_init(void)
{
return platform_driver_register(&i2c_gpio_driver);
}
device_initcall(i2c_gpio_init);

View File

@ -154,7 +154,7 @@ static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy)
if (!for_busy && !(temp & I2SR_IBB))
break;
if (is_timeout(start, 500 * MSECOND)) {
dev_err(adapter->dev,
dev_err(&adapter->dev,
"<%s> timeout waiting for I2C bus %s\n",
__func__,for_busy ? "busy" : "not busy");
return -EIO;
@ -177,7 +177,7 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
break;
if (is_timeout(start, 100 * MSECOND)) {
dev_err(adapter->dev, "<%s> TXR timeout\n", __func__);
dev_err(&adapter->dev, "<%s> TXR timeout\n", __func__);
return -EIO;
}
}
@ -199,7 +199,7 @@ static int i2c_fsl_acked(struct i2c_adapter *adapter)
break;
if (is_timeout(start, MSECOND)) {
dev_dbg(adapter->dev, "<%s> No ACK\n", __func__);
dev_dbg(&adapter->dev, "<%s> No ACK\n", __func__);
return -EIO;
}
}
@ -296,7 +296,7 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
* Translate to dfsr = 5 * Frequency / 100,000,000
*/
dfsr = (5 * (i2c_clk / 1000)) / 100000;
dev_dbg(i2c_fsl->adapter.dev,
dev_dbg(&i2c_fsl->adapter.dev,
"<%s> requested speed:%d, i2c_clk:%d\n", __func__,
rate, i2c_clk);
if (!dfsr)
@ -315,12 +315,12 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
fdr = bin_gb | bin_ga;
rate = i2c_clk / est_div;
dev_dbg(i2c_fsl->adapter.dev,
dev_dbg(&i2c_fsl->adapter.dev,
"FDR:0x%.2x, div:%ld, ga:0x%x, gb:0x%x,"
" a:%d, b:%d, speed:%d\n", fdr, est_div,
ga, gb, a, b, rate);
/* Condition 2 not accounted for */
dev_dbg(i2c_fsl->adapter.dev,
dev_dbg(&i2c_fsl->adapter.dev,
"Tr <= %d ns\n", (b - 3 * dfsr) *
1000000 / (i2c_clk / 1000));
}
@ -330,9 +330,9 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
if (a == 24)
a += 4;
}
dev_dbg(i2c_fsl->adapter.dev,
dev_dbg(&i2c_fsl->adapter.dev,
"divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
dev_dbg(i2c_fsl->adapter.dev, "FDR:0x%.2x, speed:%d\n", fdr, rate);
dev_dbg(&i2c_fsl->adapter.dev, "FDR:0x%.2x, speed:%d\n", fdr, rate);
i2c_fsl->ifdr = fdr;
i2c_fsl->dfsrr = dfsr;
}
@ -368,9 +368,9 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
(500000U * i2c_clk_div[i][0] + (i2c_clk_rate / 2) - 1) /
(i2c_clk_rate / 2);
dev_dbg(i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
dev_dbg(&i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
dev_dbg(i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
dev_dbg(&i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
}
#endif
@ -382,7 +382,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
int i, result;
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
dev_dbg(adapter->dev,
dev_dbg(&adapter->dev,
"<%s> write slave address: addr=0x%02x\n",
__func__, msgs->addr << 1);
@ -399,7 +399,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
/* write data */
for (i = 0; i < msgs->len; i++) {
dev_dbg(adapter->dev,
dev_dbg(&adapter->dev,
"<%s> write byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
writeb(msgs->buf[i], base + FSL_I2C_I2DR);
@ -425,7 +425,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
writeb(0x0, base + FSL_I2C_I2SR);
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
dev_dbg(adapter->dev,
dev_dbg(&adapter->dev,
"<%s> write slave address: addr=0x%02x\n",
__func__, (msgs->addr << 1) | 0x01);
@ -478,7 +478,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
}
msgs->buf[i] = readb(base + FSL_I2C_I2DR);
dev_dbg(adapter->dev, "<%s> read byte: B%d=0x%02X\n",
dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
}
return 0;
@ -544,7 +544,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
/* Setup i2c_fsl driver structure */
i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
i2c_fsl->adapter.nr = pdev->id;
i2c_fsl->adapter.dev = pdev;
i2c_fsl->adapter.dev.parent = pdev;
i2c_fsl->base = dev_request_mem_region(pdev, 0);
i2c_fsl->dfsrr = -1;

View File

@ -318,7 +318,7 @@ static int omap_i2c_init(struct omap_i2c_struct *i2c_omap)
while (!(omap_i2c_read_reg(i2c_omap, OMAP_I2C_SYSS_REG) &
SYSS_RESETDONE_MASK)) {
if (is_timeout(start, MSECOND)) {
dev_warn(i2c_omap->adapter.dev, "timeout waiting "
dev_warn(&i2c_omap->adapter.dev, "timeout waiting "
"for controller reset\n");
return -ETIMEDOUT;
}
@ -453,7 +453,7 @@ static int omap_i2c_wait_for_bb(struct i2c_adapter *adapter)
start = get_time_ns();
while (omap_i2c_read_reg(i2c_omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
if (is_timeout(start, MSECOND)) {
dev_warn(adapter->dev, "timeout waiting for bus ready\n");
dev_warn(&adapter->dev, "timeout waiting for bus ready\n");
return -ETIMEDOUT;
}
}
@ -476,9 +476,9 @@ omap_i2c_isr(struct omap_i2c_struct *dev)
bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
dev_dbg(dev->adapter.dev, "IRQ (ISR = 0x%04x)\n", stat);
dev_dbg(&dev->adapter.dev, "IRQ (ISR = 0x%04x)\n", stat);
if (count++ == 100) {
dev_warn(dev->adapter.dev, "Too much work in one IRQ\n");
dev_warn(&dev->adapter.dev, "Too much work in one IRQ\n");
break;
}
@ -499,7 +499,7 @@ complete:
OMAP_I2C_CON_STP);
}
if (stat & OMAP_I2C_STAT_AL) {
dev_err(dev->adapter.dev, "Arbitration lost\n");
dev_err(&dev->adapter.dev, "Arbitration lost\n");
err |= OMAP_I2C_STAT_AL;
}
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
@ -536,11 +536,11 @@ complete:
}
} else {
if (stat & OMAP_I2C_STAT_RRDY)
dev_err(dev->adapter.dev,
dev_err(&dev->adapter.dev,
"RRDY IRQ while no data"
" requested\n");
if (stat & OMAP_I2C_STAT_RDR)
dev_err(dev->adapter.dev,
dev_err(&dev->adapter.dev,
"RDR IRQ while no data"
" requested\n");
break;
@ -577,11 +577,11 @@ complete:
}
} else {
if (stat & OMAP_I2C_STAT_XRDY)
dev_err(dev->adapter.dev,
dev_err(&dev->adapter.dev,
"XRDY IRQ while no "
"data to send\n");
if (stat & OMAP_I2C_STAT_XDR)
dev_err(dev->adapter.dev,
dev_err(&dev->adapter.dev,
"XDR IRQ while no "
"data to send\n");
break;
@ -613,11 +613,11 @@ complete:
continue;
}
if (stat & OMAP_I2C_STAT_ROVR) {
dev_err(dev->adapter.dev, "Receive overrun\n");
dev_err(&dev->adapter.dev, "Receive overrun\n");
dev->cmd_err |= OMAP_I2C_STAT_ROVR;
}
if (stat & OMAP_I2C_STAT_XUDF) {
dev_err(dev->adapter.dev, "Transmit underflow\n");
dev_err(&dev->adapter.dev, "Transmit underflow\n");
dev->cmd_err |= OMAP_I2C_STAT_XUDF;
}
}
@ -639,7 +639,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
int ret = 0;
dev_dbg(adapter->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
dev_dbg(&adapter->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop);
if (msg->len == 0)
@ -687,7 +687,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
/* Let the user know if i2c is in a bad state */
if (is_timeout(start, MSECOND)) {
dev_err(adapter->dev, "controller timed out "
dev_err(&adapter->dev, "controller timed out "
"waiting for start condition to finish\n");
return -ETIMEDOUT;
}
@ -707,7 +707,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
while (ret){
ret = omap_i2c_isr(i2c_omap);
if (is_timeout(start, MSECOND)) {
dev_err(adapter->dev,
dev_err(&adapter->dev,
"timed out on polling for "
"open i2c message handling\n");
return -ETIMEDOUT;
@ -835,7 +835,7 @@ i2c_omap_probe(struct device_d *pdev)
i2c_omap->adapter.master_xfer = omap_i2c_xfer,
i2c_omap->adapter.nr = pdev->id;
i2c_omap->adapter.dev = pdev;
i2c_omap->adapter.dev.parent = pdev;
/* i2c device drivers may be active on return from add_adapter() */
r = i2c_add_numbered_adapter(&i2c_omap->adapter);

View File

@ -0,0 +1,112 @@
/*
* i2c-versatile.c
*
* Copyright (C) 2006 ARM Ltd.
* written by Russell King, Deep Blue Solutions Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <common.h>
#include <driver.h>
#include <i2c/i2c.h>
#include <i2c/i2c-algo-bit.h>
#include <init.h>
#include <malloc.h>
#include <io.h>
#define I2C_CONTROL 0x00
#define I2C_CONTROLS 0x00
#define I2C_CONTROLC 0x04
#define SCL (1 << 0)
#define SDA (1 << 1)
struct i2c_versatile {
struct i2c_adapter adap;
struct i2c_algo_bit_data algo;
void __iomem *base;
};
static void i2c_versatile_setsda(void *data, int state)
{
struct i2c_versatile *i2c = data;
writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
}
static void i2c_versatile_setscl(void *data, int state)
{
struct i2c_versatile *i2c = data;
writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
}
static int i2c_versatile_getsda(void *data)
{
struct i2c_versatile *i2c = data;
return !!(readl(i2c->base + I2C_CONTROL) & SDA);
}
static int i2c_versatile_getscl(void *data)
{
struct i2c_versatile *i2c = data;
return !!(readl(i2c->base + I2C_CONTROL) & SCL);
}
static struct i2c_algo_bit_data i2c_versatile_algo = {
.setsda = i2c_versatile_setsda,
.setscl = i2c_versatile_setscl,
.getsda = i2c_versatile_getsda,
.getscl = i2c_versatile_getscl,
.udelay = 30,
.timeout_ms = 100,
};
static int i2c_versatile_probe(struct device_d *dev)
{
struct i2c_versatile *i2c;
int ret;
i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
if (!i2c) {
ret = -ENOMEM;
goto err_release;
}
i2c->base = dev_request_mem_region(dev, 0);
if (!i2c->base) {
ret = -ENOMEM;
goto err_free;
}
writel(SCL | SDA, i2c->base + I2C_CONTROLS);
i2c->adap.algo_data = &i2c->algo;
i2c->adap.dev.parent = dev;
i2c->algo = i2c_versatile_algo;
i2c->algo.data = i2c;
i2c->adap.nr = dev->id;
ret = i2c_bit_add_numbered_bus(&i2c->adap);
if (ret >= 0) {
return 0;
}
err_free:
kfree(i2c);
err_release:
return ret;
}
static struct driver_d i2c_versatile_driver = {
.name = "versatile-i2c",
.probe = i2c_versatile_probe,
};
static int __init i2c_versatile_init(void)
{
return platform_driver_register(&i2c_versatile_driver);
}
device_initcall(i2c_versatile_init);

View File

@ -80,7 +80,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
*/
for (ret = 0; ret < num; ret++) {
dev_dbg(adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d\n", ret, (msgs[ret].flags & I2C_M_RD)
? 'R' : 'W', msgs[ret].addr, msgs[ret].len);
}
@ -256,6 +256,9 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
client->adapter = adapter;
client->addr = chip->addr;
client->dev.parent = &adapter->dev;
dev_add_child(client->dev.parent, &client->dev);
status = register_device(&client->dev);
#if 0
@ -278,6 +281,34 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
}
EXPORT_SYMBOL(i2c_new_device);
/**
* i2c_new_dummy - return a new i2c device bound to a dummy driver
* @adapter: the adapter managing the device
* @address: seven bit address to be used
* Context: can sleep
*
* This returns an I2C client bound to the "dummy" driver, intended for use
* with devices that consume multiple addresses. Examples of such chips
* include various EEPROMS (like 24c04 and 24c08 models).
*
* These dummy devices have two main uses. First, most I2C and SMBus calls
* except i2c_transfer() need a client handle; the dummy will be that handle.
* And second, this prevents the specified address from being bound to a
* different driver.
*
* This returns the new i2c client, which should be saved for later use with
* i2c_unregister_device(); or NULL to indicate an error.
*/
struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
{
struct i2c_board_info info = {
I2C_BOARD_INFO("dummy", address),
};
return i2c_new_device(adapter, &info);
}
EXPORT_SYMBOL_GPL(i2c_new_dummy);
/**
* i2c_register_board_info - register I2C devices for a given board
*
@ -363,9 +394,21 @@ struct i2c_adapter *i2c_get_adapter(int busnum)
*/
int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
{
int ret;
if (i2c_get_adapter(adapter->nr))
return -EBUSY;
adapter->dev.id = adapter->nr;
strcpy(adapter->dev.name, "i2c");
if (adapter->dev.parent)
dev_add_child(adapter->dev.parent, &adapter->dev);
ret = register_device(&adapter->dev);
if (ret)
return ret;
list_add_tail(&adapter->list, &adapter_list);
/* populate children from any i2c device tables */
@ -377,7 +420,22 @@ EXPORT_SYMBOL(i2c_add_numbered_adapter);
static int i2c_match(struct device_d *dev, struct driver_d *drv)
{
return strcmp(dev->name, drv->name) ? -1 : 0;
if (!strcmp(dev->name, drv->name))
return 0;
if (drv->id_table) {
struct platform_device_id *id = drv->id_table;
while (id->name) {
if (!strcmp(id->name, dev->name)) {
dev->id_entry = id;
return 0;
}
id++;
}
}
return -1;
}
static int i2c_probe(struct device_d *dev)

35
include/i2c/at24.h Normal file
View File

@ -0,0 +1,35 @@
/*
* at24.h - platform_data for the at24 (generic eeprom) driver
* (C) Copyright 2008 by Pengutronix
* (C) Copyright 2012 by Wolfram Sang
* same license as the driver
*/
#ifndef _LINUX_AT24_H
#define _LINUX_AT24_H
#include <linux/types.h>
/**
* struct at24_platform_data - data to set up at24 (generic eeprom) driver
* @byte_len: size of eeprom in byte
* @page_size: number of byte which can be written in one go
* @flags: tunable options, check AT24_FLAG_* defines
*
* If you set up a custom eeprom type, please double-check the parameters.
* Especially page_size needs extra care, as you risk data loss if your value
* is bigger than what the chip actually supports!
*
*/
struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
u8 flags;
#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
};
#endif /* _LINUX_AT24_H */

View File

@ -0,0 +1,55 @@
/* ------------------------------------------------------------------------- */
/* i2c-algo-bit.h i2c driver algorithms for bit-shift adapters */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-99 Simon G. Vogl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA. */
/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
#ifndef _LINUX_I2C_ALGO_BIT_H
#define _LINUX_I2C_ALGO_BIT_H
/* --- Defines for bit-adapters --------------------------------------- */
/*
* This struct contains the hw-dependent functions of bit-style adapters to
* manipulate the line states, and to init any hw-specific features. This is
* only used if you have more than one hw-type of adapter running.
*/
struct i2c_algo_bit_data {
void *data; /* private data for lowlevel routines */
void (*setsda) (void *data, int state);
void (*setscl) (void *data, int state);
int (*getsda) (void *data);
int (*getscl) (void *data);
int (*pre_xfer) (struct i2c_adapter *);
void (*post_xfer) (struct i2c_adapter *);
/* local settings */
int udelay; /* half clock cycle time in us,
minimum 2 us for fast-mode I2C,
minimum 5 us for standard-mode I2C and SMBus,
maximum 50 us for SMBus */
int timeout_ms; /* in ms */
};
int i2c_bit_add_bus(struct i2c_adapter *);
int i2c_bit_add_numbered_bus(struct i2c_adapter *);
extern const struct i2c_algorithm i2c_bit_algo;
#endif /* _LINUX_I2C_ALGO_BIT_H */

38
include/i2c/i2c-gpio.h Normal file
View File

@ -0,0 +1,38 @@
/*
* i2c-gpio interface to platform code
*
* Copyright (C) 2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _LINUX_I2C_GPIO_H
#define _LINUX_I2C_GPIO_H
/**
* struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
* @sda_pin: GPIO pin ID to use for SDA
* @scl_pin: GPIO pin ID to use for SCL
* @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
* @timeout_ms: clock stretching timeout in ms. If the slave keeps
* SCL low for longer than this, the transfer will time out.
* @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
* isn't actively driven high when setting the output value high.
* gpio_get_value() must return the actual pin state even if the
* pin is configured as an output.
* @scl_is_open_drain: SCL is set up as open drain. Same requirements
* as for sda_is_open_drain apply.
* @scl_is_output_only: SCL output drivers cannot be turned off.
*/
struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
int udelay;
int timeout_ms;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
};
#endif /* _LINUX_I2C_GPIO_H */

View File

@ -66,10 +66,12 @@ struct i2c_msg {
*
*/
struct i2c_adapter {
struct device_d *dev; /* ptr to device */
struct device_d dev; /* ptr to device */
int nr; /* bus number */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
struct list_head list;
int retries;
void *algo_data;
};
@ -127,6 +129,14 @@ static inline int i2c_register_board_info(int busnum,
extern int i2c_add_numbered_adapter(struct i2c_adapter *adapter);
struct i2c_adapter *i2c_get_adapter(int busnum);
/* For devices that use several addresses, use i2c_new_dummy() to make
* client handles for the extra addresses.
*/
extern struct i2c_client *
i2c_new_dummy(struct i2c_adapter *adap, u16 address);
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
extern int i2c_master_send(struct i2c_client *client, const char *buf, int count);
extern int i2c_master_recv(struct i2c_client *client, char *buf, int count);

View File

@ -90,5 +90,20 @@
__val = __val < __min ? __min: __val; \
__val > __max ? __max: __val; })
/* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
#define roundup(x, y) ( \
{ \
const typeof(y) __y = y; \
(((x) + (__y - 1)) / __y) * __y; \
} \
)
#define rounddown(x, y) ( \
{ \
typeof(x) __x = (x); \
__x - (__x % (y)); \
} \
)
#endif /* _LINUX_KERNEL_H */

190
include/linux/log2.h Normal file
View File

@ -0,0 +1,190 @@
/* Integer base 2 logarithm calculation
*
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _LINUX_LOG2_H
#define _LINUX_LOG2_H
#include <linux/types.h>
#include <linux/bitops.h>
/*
* deal with unrepresentable constant logarithms
*/
extern __attribute__((const, noreturn))
int ____ilog2_NaN(void);
/*
* non-constant log of base 2 calculators
* - the arch may override these in asm/bitops.h if they can be implemented
* more efficiently than using fls() and fls64()
* - the arch is not required to handle n==0 if implementing the fallback
*/
#ifndef CONFIG_ARCH_HAS_ILOG2_U32
static inline __attribute__((const))
int __ilog2_u32(u32 n)
{
return fls(n) - 1;
}
#endif
#ifndef CONFIG_ARCH_HAS_ILOG2_U64
static inline __attribute__((const))
int __ilog2_u64(u64 n)
{
return fls64(n) - 1;
}
#endif
/*
* Determine whether some value is a power of two, where zero is
* *not* considered a power of two.
*/
static inline __attribute__((const))
bool is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
/**
* ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
* @n - parameter
*
* constant-capable log of base 2 calculation
* - this can be used to initialise global variables from constant data, hence
* the massive ternary operator construction
*
* selects the appropriately-sized optimised version depending on sizeof(n)
*/
#define ilog2(n) \
( \
__builtin_constant_p(n) ? ( \
(n) < 1 ? ____ilog2_NaN() : \
(n) & (1ULL << 63) ? 63 : \
(n) & (1ULL << 62) ? 62 : \
(n) & (1ULL << 61) ? 61 : \
(n) & (1ULL << 60) ? 60 : \
(n) & (1ULL << 59) ? 59 : \
(n) & (1ULL << 58) ? 58 : \
(n) & (1ULL << 57) ? 57 : \
(n) & (1ULL << 56) ? 56 : \
(n) & (1ULL << 55) ? 55 : \
(n) & (1ULL << 54) ? 54 : \
(n) & (1ULL << 53) ? 53 : \
(n) & (1ULL << 52) ? 52 : \
(n) & (1ULL << 51) ? 51 : \
(n) & (1ULL << 50) ? 50 : \
(n) & (1ULL << 49) ? 49 : \
(n) & (1ULL << 48) ? 48 : \
(n) & (1ULL << 47) ? 47 : \
(n) & (1ULL << 46) ? 46 : \
(n) & (1ULL << 45) ? 45 : \
(n) & (1ULL << 44) ? 44 : \
(n) & (1ULL << 43) ? 43 : \
(n) & (1ULL << 42) ? 42 : \
(n) & (1ULL << 41) ? 41 : \
(n) & (1ULL << 40) ? 40 : \
(n) & (1ULL << 39) ? 39 : \
(n) & (1ULL << 38) ? 38 : \
(n) & (1ULL << 37) ? 37 : \
(n) & (1ULL << 36) ? 36 : \
(n) & (1ULL << 35) ? 35 : \
(n) & (1ULL << 34) ? 34 : \
(n) & (1ULL << 33) ? 33 : \
(n) & (1ULL << 32) ? 32 : \
(n) & (1ULL << 31) ? 31 : \
(n) & (1ULL << 30) ? 30 : \
(n) & (1ULL << 29) ? 29 : \
(n) & (1ULL << 28) ? 28 : \
(n) & (1ULL << 27) ? 27 : \
(n) & (1ULL << 26) ? 26 : \
(n) & (1ULL << 25) ? 25 : \
(n) & (1ULL << 24) ? 24 : \
(n) & (1ULL << 23) ? 23 : \
(n) & (1ULL << 22) ? 22 : \
(n) & (1ULL << 21) ? 21 : \
(n) & (1ULL << 20) ? 20 : \
(n) & (1ULL << 19) ? 19 : \
(n) & (1ULL << 18) ? 18 : \
(n) & (1ULL << 17) ? 17 : \
(n) & (1ULL << 16) ? 16 : \
(n) & (1ULL << 15) ? 15 : \
(n) & (1ULL << 14) ? 14 : \
(n) & (1ULL << 13) ? 13 : \
(n) & (1ULL << 12) ? 12 : \
(n) & (1ULL << 11) ? 11 : \
(n) & (1ULL << 10) ? 10 : \
(n) & (1ULL << 9) ? 9 : \
(n) & (1ULL << 8) ? 8 : \
(n) & (1ULL << 7) ? 7 : \
(n) & (1ULL << 6) ? 6 : \
(n) & (1ULL << 5) ? 5 : \
(n) & (1ULL << 4) ? 4 : \
(n) & (1ULL << 3) ? 3 : \
(n) & (1ULL << 2) ? 2 : \
(n) & (1ULL << 1) ? 1 : \
(n) & (1ULL << 0) ? 0 : \
____ilog2_NaN() \
) : \
(sizeof(n) <= 4) ? \
__ilog2_u32(n) : \
__ilog2_u64(n) \
)
/**
* roundup_pow_of_two - round the given value up to nearest power of two
* @n - parameter
*
* round the given value up to the nearest power of two
* - the result is undefined when n == 0
* - this can be used to initialise global variables from constant data
*/
#define roundup_pow_of_two(n) \
( \
__builtin_constant_p(n) ? ( \
(n == 1) ? 1 : \
(1UL << (ilog2((n) - 1) + 1)) \
) : \
__roundup_pow_of_two(n) \
)
/**
* rounddown_pow_of_two - round the given value down to nearest power of two
* @n - parameter
*
* round the given value down to the nearest power of two
* - the result is undefined when n == 0
* - this can be used to initialise global variables from constant data
*/
#define rounddown_pow_of_two(n) \
( \
__builtin_constant_p(n) ? ( \
(1UL << ilog2(n))) : \
__rounddown_pow_of_two(n) \
)
/**
* order_base_2 - calculate the (rounded up) base 2 order of the argument
* @n: parameter
*
* The first few values calculated by this routine:
* ob2(0) = 0
* ob2(1) = 0
* ob2(2) = 1
* ob2(3) = 2
* ob2(4) = 2
* ob2(5) = 3
* ... and so on.
*/
#define order_base_2(n) ilog2(roundup_pow_of_two(n))
#endif /* _LINUX_LOG2_H */

121
include/linux/math64.h Normal file
View File

@ -0,0 +1,121 @@
#ifndef _LINUX_MATH64_H
#define _LINUX_MATH64_H
#include <linux/types.h>
#include <asm-generic/div64.h>
#if BITS_PER_LONG == 64
#define div64_long(x,y) div64_s64((x),(y))
/**
* div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
*
* This is commonly provided by 32bit archs to provide an optimized 64bit
* divide.
*/
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* div_s64_rem - signed 64bit divide with 32bit divisor with remainder
*/
static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* div64_u64 - unsigned 64bit divide with 64bit divisor
*/
static inline u64 div64_u64(u64 dividend, u64 divisor)
{
return dividend / divisor;
}
/**
* div64_s64 - signed 64bit divide with 64bit divisor
*/
static inline s64 div64_s64(s64 dividend, s64 divisor)
{
return dividend / divisor;
}
#elif BITS_PER_LONG == 32
#define div64_long(x,y) div_s64((x),(y))
#ifndef div_u64_rem
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
*remainder = do_div(dividend, divisor);
return dividend;
}
#endif
#ifndef div_s64_rem
extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
#endif
#ifndef div64_u64
extern u64 div64_u64(u64 dividend, u64 divisor);
#endif
#ifndef div64_s64
extern s64 div64_s64(s64 dividend, s64 divisor);
#endif
#endif /* BITS_PER_LONG */
/**
* div_u64 - unsigned 64bit divide with 32bit divisor
*
* This is the most common 64bit divide and should be used if possible,
* as many 32bit archs can optimize this variant better than a full 64bit
* divide.
*/
#ifndef div_u64
static inline u64 div_u64(u64 dividend, u32 divisor)
{
u32 remainder;
return div_u64_rem(dividend, divisor, &remainder);
}
#endif
/**
* div_s64 - signed 64bit divide with 32bit divisor
*/
#ifndef div_s64
static inline s64 div_s64(s64 dividend, s32 divisor)
{
s32 remainder;
return div_s64_rem(dividend, divisor, &remainder);
}
#endif
u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
static __always_inline u32
__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
{
u32 ret = 0;
while (dividend >= divisor) {
/* The following asm() prevents the compiler from
optimising this loop into a modulo operation. */
asm("" : "+rm"(dividend));
dividend -= divisor;
ret++;
}
*remainder = dividend;
return ret;
}
#endif /* _LINUX_MATH64_H */