/drivers/video/drm/i2c/i2c-algo-bit.c |
---|
15,7 → 15,8 |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
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 |
24,11 → 25,13 |
#include <types.h> |
#include <list.h> |
#include <linux/kernel.h> |
#include <linux/spinlock.h> |
#include <syscall.h> |
#include <errno.h> |
#include <linux/i2c.h> |
#include <linux/i2c-algo-bit.h> |
#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */ |
/* ----- global defines ----------------------------------------------- */ |
40,13 → 43,19 |
} while (0) |
#else |
#define bit_dbg(level, dev, format, args...) \ |
do {} while (0) |
do { /* dbgprintf(format, ##args); */ } while (0) |
#endif /* DEBUG */ |
/* ----- global variables --------------------------------------------- */ |
static int bit_test; /* see if the line-setting functions work */ |
static int bit_test = 0; /* see if the line-setting functions work */ |
#ifdef DEBUG |
static int i2c_debug = 1; |
module_param(i2c_debug, int, S_IRUGO | S_IWUSR); |
MODULE_PARM_DESC(i2c_debug, |
"debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); |
#endif |
/* --- setting states on the bus with the right timing: --------------- */ |
87,7 → 96,7 |
if (!adap->getscl) |
goto done; |
// start = jiffies; |
start = GetTimerTicks(); |
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 |
94,19 → 103,16 |
* chips may hold it low ("clock stretching") while they |
* are processing data internally. |
*/ |
// if (time_after(jiffies, start + adap->timeout)) |
// return -ETIMEDOUT; |
udelay(adap->udelay); |
// cond_resched(); |
if (time_after(GetTimerTicks(), start + adap->timeout)) { |
/* 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 |
udelay(1); |
} |
done: |
udelay(adap->udelay); |
return 0; |
239,12 → 245,14 |
} |
if (adap->getscl == NULL) |
pr_info("%s: Testing SDA only, SCL is not readable\n", name); |
dbgprintf("%s: Testing SDA only, SCL is not readable\n", name); |
sda = getsda(adap); |
scl = (adap->getscl == NULL) ? 1 : getscl(adap); |
if (!scl || !sda) { |
printk(KERN_WARNING "%s: bus seems to be busy\n", name); |
printk(KERN_WARNING |
"%s: bus seems to be busy (scl=%d, sda=%d)\n", |
name, scl, sda); |
goto bailout; |
} |
303,7 → 311,7 |
if (adap->post_xfer) |
adap->post_xfer(i2c_adap); |
pr_info("%s: Test OK\n", name); |
dbgprintf("%s: Test OK\n", name); |
return 0; |
bailout: |
sdahi(adap); |
372,7 → 380,7 |
* the SMBus PEC was wrong. |
*/ |
} else if (retval == 0) { |
// dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); |
dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); |
return -EIO; |
/* Timeout; or (someday) lost arbitration |
383,8 → 391,8 |
* to know or care about this ... it is *NOT* an error. |
*/ |
} else { |
// dev_err(&i2c_adap->dev, "sendbytes: error %d\n", |
// retval); |
dev_err(&i2c_adap->dev, "sendbytes: error %d\n", |
retval); |
return retval; |
} |
} |
400,8 → 408,8 |
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; |
dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); |
return -ETIMEDOUT; |
} |
scllo(adap); |
return 0; |
433,9 → 441,9 |
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { |
if (!(flags & I2C_M_NO_RD_ACK)) |
acknak(i2c_adap, 0); |
// dev_err(&i2c_adap->dev, "readbytes: invalid " |
// "block length (%d)\n", inval); |
return -EREMOTEIO; |
dev_err(&i2c_adap->dev, "readbytes: invalid " |
"block length (%d)\n", inval); |
return -EPROTO; |
} |
/* The original count value accounts for the extra |
bytes, that is, either 1 for a regular transaction, |
464,7 → 472,7 |
* 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: -EREMOTEIO if the device did not answer, or |
* -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) |
480,21 → 488,21 |
if (flags & I2C_M_TEN) { |
/* a ten bit address */ |
addr = 0xf0 | ((msg->addr >> 7) & 0x03); |
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 -EREMOTEIO; |
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 & 0x7f); |
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 -EREMOTEIO; |
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 " |
504,9 → 512,9 |
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 -EREMOTEIO; |
dev_err(&i2c_adap->dev, |
"died at repeated address code\n"); |
return -EIO; |
} |
} |
} else { /* normal 7bit address */ |
531,7 → 539,6 |
int i, ret; |
unsigned short nak_ok; |
//ENTER(); |
if (adap->pre_xfer) { |
ret = adap->pre_xfer(i2c_adap); |
if (ret < 0) |
565,7 → 572,7 |
ret, ret == 1 ? "" : "s"); |
if (ret < pmsg->len) { |
if (ret >= 0) |
ret = -EREMOTEIO; |
ret = -EIO; |
goto bailout; |
} |
} else { |
576,7 → 583,7 |
ret, ret == 1 ? "" : "s"); |
if (ret < pmsg->len) { |
if (ret >= 0) |
ret = -EREMOTEIO; |
ret = -EIO; |
goto bailout; |
} |
} |
586,7 → 593,6 |
bailout: |
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); |
i2c_stop(adap); |
// LEAVE(); |
if (adap->post_xfer) |
adap->post_xfer(i2c_adap); |
595,7 → 601,7 |
static u32 bit_func(struct i2c_adapter *adap) |
{ |
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | |
return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | |
I2C_FUNC_SMBUS_READ_BLOCK_DATA | |
I2C_FUNC_SMBUS_BLOCK_PROC_CALL | |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; |
604,10 → 610,11 |
/* -----exported algorithm data: ------------------------------------- */ |
static const struct i2c_algorithm i2c_bit_algo = { |
const struct i2c_algorithm i2c_bit_algo = { |
.master_xfer = bit_xfer, |
.functionality = bit_func, |
}; |
EXPORT_SYMBOL(i2c_bit_algo); |
/* |
* registering functions to load algorithms at runtime |
620,7 → 627,7 |
if (bit_test) { |
ret = test_bus(adap); |
if (ret < 0) |
if (bit_test >= 2 && ret < 0) |
return -ENODEV; |
} |
628,6 → 635,11 |
adap->algo = &i2c_bit_algo; |
adap->retries = 3; |
/* 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; |
} |
/drivers/video/drm/i2c/i2c-core.c |
---|
14,15 → 14,20 |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
MA 02110-1301 USA. */ |
/* ------------------------------------------------------------------------- */ |
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. |
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> |
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and |
Jean Delvare <khali@linux-fr.org> */ |
Jean Delvare <khali@linux-fr.org> |
Mux support by Rodolfo Giometti <giometti@enneenne.com> and |
Michael Lawnick <michael.lawnick.ext@nsn.com> */ |
#include <types.h> |
#include <linux/module.h> |
#include <linux/kernel.h> |
#include <linux/spinlock.h> |
#include <list.h> |
#include <errno.h> |
#include <linux/i2c.h> |
29,7 → 34,254 |
#include <syscall.h> |
#if 0 |
static ssize_t |
show_modalias(struct device *dev, struct device_attribute *attr, char *buf) |
{ |
struct i2c_client *client = to_i2c_client(dev); |
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); |
} |
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); |
static struct attribute *i2c_dev_attrs[] = { |
&dev_attr_name.attr, |
/* modalias helps coldplug: modprobe $(cat .../modalias) */ |
&dev_attr_modalias.attr, |
NULL |
}; |
static struct attribute_group i2c_dev_attr_group = { |
.attrs = i2c_dev_attrs, |
}; |
static const struct attribute_group *i2c_dev_attr_groups[] = { |
&i2c_dev_attr_group, |
NULL |
}; |
static const struct dev_pm_ops i2c_device_pm_ops = { |
.suspend = i2c_device_pm_suspend, |
.resume = i2c_device_pm_resume, |
.freeze = i2c_device_pm_freeze, |
.thaw = i2c_device_pm_thaw, |
.poweroff = i2c_device_pm_poweroff, |
.restore = i2c_device_pm_restore, |
SET_RUNTIME_PM_OPS( |
pm_generic_runtime_suspend, |
pm_generic_runtime_resume, |
pm_generic_runtime_idle |
) |
}; |
struct bus_type i2c_bus_type = { |
.name = "i2c", |
.match = i2c_device_match, |
.probe = i2c_device_probe, |
.remove = i2c_device_remove, |
.shutdown = i2c_device_shutdown, |
.pm = &i2c_device_pm_ops, |
}; |
EXPORT_SYMBOL_GPL(i2c_bus_type); |
static struct device_type i2c_client_type = { |
.groups = i2c_dev_attr_groups, |
.uevent = i2c_device_uevent, |
.release = i2c_client_dev_release, |
}; |
/** |
* i2c_verify_client - return parameter as i2c_client, or NULL |
* @dev: device, probably from some driver model iterator |
* |
* When traversing the driver model tree, perhaps using driver model |
* iterators like @device_for_each_child(), you can't assume very much |
* about the nodes you find. Use this function to avoid oopses caused |
* by wrongly treating some non-I2C device as an i2c_client. |
*/ |
struct i2c_client *i2c_verify_client(struct device *dev) |
{ |
return (dev->type == &i2c_client_type) |
? to_i2c_client(dev) |
: NULL; |
} |
EXPORT_SYMBOL(i2c_verify_client); |
/* This is a permissive address validity check, I2C address map constraints |
* are purposely not enforced, except for the general call address. */ |
static int i2c_check_client_addr_validity(const struct i2c_client *client) |
{ |
if (client->flags & I2C_CLIENT_TEN) { |
/* 10-bit address, all values are valid */ |
if (client->addr > 0x3ff) |
return -EINVAL; |
} else { |
/* 7-bit address, reject the general call address */ |
if (client->addr == 0x00 || client->addr > 0x7f) |
return -EINVAL; |
} |
return 0; |
} |
/* And this is a strict address validity check, used when probing. If a |
* device uses a reserved address, then it shouldn't be probed. 7-bit |
* addressing is assumed, 10-bit address devices are rare and should be |
* explicitly enumerated. */ |
static int i2c_check_addr_validity(unsigned short addr) |
{ |
/* |
* Reserved addresses per I2C specification: |
* 0x00 General call address / START byte |
* 0x01 CBUS address |
* 0x02 Reserved for different bus format |
* 0x03 Reserved for future purposes |
* 0x04-0x07 Hs-mode master code |
* 0x78-0x7b 10-bit slave addressing |
* 0x7c-0x7f Reserved for future purposes |
*/ |
if (addr < 0x08 || addr > 0x77) |
return -EINVAL; |
return 0; |
} |
static int __i2c_check_addr_busy(struct device *dev, void *addrp) |
{ |
struct i2c_client *client = i2c_verify_client(dev); |
int addr = *(int *)addrp; |
if (client && client->addr == addr) |
return -EBUSY; |
return 0; |
} |
/* walk up mux tree */ |
static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr) |
{ |
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); |
int result; |
result = device_for_each_child(&adapter->dev, &addr, |
__i2c_check_addr_busy); |
if (!result && parent) |
result = i2c_check_mux_parents(parent, addr); |
return result; |
} |
/* recurse down mux tree */ |
static int i2c_check_mux_children(struct device *dev, void *addrp) |
{ |
int result; |
if (dev->type == &i2c_adapter_type) |
result = device_for_each_child(dev, addrp, |
i2c_check_mux_children); |
else |
result = __i2c_check_addr_busy(dev, addrp); |
return result; |
} |
static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) |
{ |
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); |
int result = 0; |
if (parent) |
result = i2c_check_mux_parents(parent, addr); |
if (!result) |
result = device_for_each_child(&adapter->dev, &addr, |
i2c_check_mux_children); |
return result; |
} |
/** |
* i2c_lock_adapter - Get exclusive access to an I2C bus segment |
* @adapter: Target I2C bus segment |
*/ |
void i2c_lock_adapter(struct i2c_adapter *adapter) |
{ |
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); |
if (parent) |
i2c_lock_adapter(parent); |
else |
rt_mutex_lock(&adapter->bus_lock); |
} |
EXPORT_SYMBOL_GPL(i2c_lock_adapter); |
/** |
* i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment |
* @adapter: Target I2C bus segment |
*/ |
static int i2c_trylock_adapter(struct i2c_adapter *adapter) |
{ |
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); |
if (parent) |
return i2c_trylock_adapter(parent); |
else |
return rt_mutex_trylock(&adapter->bus_lock); |
} |
/** |
* i2c_unlock_adapter - Release exclusive access to an I2C bus segment |
* @adapter: Target I2C bus segment |
*/ |
void i2c_unlock_adapter(struct i2c_adapter *adapter) |
{ |
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); |
if (parent) |
i2c_unlock_adapter(parent); |
else |
rt_mutex_unlock(&adapter->bus_lock); |
} |
EXPORT_SYMBOL_GPL(i2c_unlock_adapter); |
#endif |
/** |
* i2c_transfer - execute a single or combined I2C message |
* @adap: Handle to I2C bus |
* @msgs: One or more messages to execute before STOP is issued to |
65,22 → 317,24 |
if (adap->algo->master_xfer) { |
/* Retry automatically on arbitration loss */ |
orig_jiffies = GetTimerTicks(); |
/* Retry automatically on arbitration loss */ |
orig_jiffies = 0; |
for (ret = 0, try = 0; try <= adap->retries; try++) { |
ret = adap->algo->master_xfer(adap, msgs, num); |
if (ret != -EAGAIN) |
break; |
// if (time_after(jiffies, orig_jiffies + adap->timeout)) |
// break; |
if (time_after(GetTimerTicks(), orig_jiffies + adap->timeout)) |
break; |
delay(1); |
} |
// mutex_unlock(&adap->bus_lock); |
return ret; |
} else { |
// dev_dbg(&adap->dev, "I2C level transfers not supported\n"); |
dbgprintf("I2C level transfers not supported\n"); |
return -EOPNOTSUPP; |
} |
} |