Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: - regression fixes for i801 and designware - better API and leak fix for releasing DMA safe buffers - better greppable strings for the bitbang algorithm * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: sh_mobile: fix leak when using DMA bounce buffer i2c: sh_mobile: define start_ch() void as it only returns 0 anyhow i2c: refactor function to release a DMA safe buffer i2c: algos: bit: make the error messages grepable i2c: designware: Re-init controllers with pm_disabled set on resume i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus
This commit is contained in:
Коммит
754cf4b243
|
@ -50,10 +50,14 @@ bounce buffer. But you don't need to care about that detail, just use the
|
||||||
returned buffer. If NULL is returned, the threshold was not met or a bounce
|
returned buffer. If NULL is returned, the threshold was not met or a bounce
|
||||||
buffer could not be allocated. Fall back to PIO in that case.
|
buffer could not be allocated. Fall back to PIO in that case.
|
||||||
|
|
||||||
In any case, a buffer obtained from above needs to be released. It ensures data
|
In any case, a buffer obtained from above needs to be released. Another helper
|
||||||
is copied back to the message and a potentially used bounce buffer is freed::
|
function ensures a potentially used bounce buffer is freed::
|
||||||
|
|
||||||
i2c_release_dma_safe_msg_buf(msg, dma_buf);
|
i2c_put_dma_safe_msg_buf(dma_buf, msg, xferred);
|
||||||
|
|
||||||
|
The last argument 'xferred' controls if the buffer is synced back to the
|
||||||
|
message or not. No syncing is needed in cases setting up DMA had an error and
|
||||||
|
there was no data transferred.
|
||||||
|
|
||||||
The bounce buffer handling from the core is generic and simple. It will always
|
The bounce buffer handling from the core is generic and simple. It will always
|
||||||
allocate a new bounce buffer. If you want a more sophisticated handling (e.g.
|
allocate a new bounce buffer. If you want a more sophisticated handling (e.g.
|
||||||
|
|
|
@ -110,8 +110,8 @@ static int sclhi(struct i2c_algo_bit_data *adap)
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (jiffies != start && i2c_debug >= 3)
|
if (jiffies != start && i2c_debug >= 3)
|
||||||
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
|
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go high\n",
|
||||||
"high\n", jiffies - start);
|
jiffies - start);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -171,8 +171,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
|
||||||
setsda(adap, sb);
|
setsda(adap, sb);
|
||||||
udelay((adap->udelay + 1) / 2);
|
udelay((adap->udelay + 1) / 2);
|
||||||
if (sclhi(adap) < 0) { /* timed out */
|
if (sclhi(adap) < 0) { /* timed out */
|
||||||
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
|
bit_dbg(1, &i2c_adap->dev,
|
||||||
"timeout at bit #%d\n", (int)c, i);
|
"i2c_outb: 0x%02x, timeout at bit #%d\n",
|
||||||
|
(int)c, i);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
/* FIXME do arbitration here:
|
/* FIXME do arbitration here:
|
||||||
|
@ -185,8 +186,8 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
|
||||||
}
|
}
|
||||||
sdahi(adap);
|
sdahi(adap);
|
||||||
if (sclhi(adap) < 0) { /* timeout */
|
if (sclhi(adap) < 0) { /* timeout */
|
||||||
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
|
bit_dbg(1, &i2c_adap->dev,
|
||||||
"timeout at ack\n", (int)c);
|
"i2c_outb: 0x%02x, timeout at ack\n", (int)c);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +216,9 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
|
||||||
sdahi(adap);
|
sdahi(adap);
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if (sclhi(adap) < 0) { /* timeout */
|
if (sclhi(adap) < 0) { /* timeout */
|
||||||
bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
|
bit_dbg(1, &i2c_adap->dev,
|
||||||
"#%d\n", 7 - i);
|
"i2c_inb: timeout at bit #%d\n",
|
||||||
|
7 - i);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
indata *= 2;
|
indata *= 2;
|
||||||
|
@ -265,8 +267,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
if (!scl) {
|
if (!scl) {
|
||||||
printk(KERN_WARNING "%s: SCL unexpected low "
|
printk(KERN_WARNING
|
||||||
"while pulling SDA low!\n", name);
|
"%s: SCL unexpected low while pulling SDA low!\n",
|
||||||
|
name);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +281,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
if (!scl) {
|
if (!scl) {
|
||||||
printk(KERN_WARNING "%s: SCL unexpected low "
|
printk(KERN_WARNING
|
||||||
"while pulling SDA high!\n", name);
|
"%s: SCL unexpected low while pulling SDA high!\n",
|
||||||
|
name);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,8 +295,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
if (!sda) {
|
if (!sda) {
|
||||||
printk(KERN_WARNING "%s: SDA unexpected low "
|
printk(KERN_WARNING
|
||||||
"while pulling SCL low!\n", name);
|
"%s: SDA unexpected low while pulling SCL low!\n",
|
||||||
|
name);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,8 +309,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
if (!sda) {
|
if (!sda) {
|
||||||
printk(KERN_WARNING "%s: SDA unexpected low "
|
printk(KERN_WARNING
|
||||||
"while pulling SCL high!\n", name);
|
"%s: SDA unexpected low while pulling SCL high!\n",
|
||||||
|
name);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,8 +358,8 @@ static int try_address(struct i2c_adapter *i2c_adap,
|
||||||
i2c_start(adap);
|
i2c_start(adap);
|
||||||
}
|
}
|
||||||
if (i && ret)
|
if (i && ret)
|
||||||
bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
|
bit_dbg(1, &i2c_adap->dev,
|
||||||
"0x%02x: %s\n", i + 1,
|
"Used %d tries to %s client at 0x%02x: %s\n", i + 1,
|
||||||
addr & 1 ? "read from" : "write to", addr >> 1,
|
addr & 1 ? "read from" : "write to", addr >> 1,
|
||||||
ret == 1 ? "success" : "failed, timeout?");
|
ret == 1 ? "success" : "failed, timeout?");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -442,8 +448,9 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||||
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
|
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
|
||||||
if (!(flags & I2C_M_NO_RD_ACK))
|
if (!(flags & I2C_M_NO_RD_ACK))
|
||||||
acknak(i2c_adap, 0);
|
acknak(i2c_adap, 0);
|
||||||
dev_err(&i2c_adap->dev, "readbytes: invalid "
|
dev_err(&i2c_adap->dev,
|
||||||
"block length (%d)\n", inval);
|
"readbytes: invalid block length (%d)\n",
|
||||||
|
inval);
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
}
|
}
|
||||||
/* The original count value accounts for the extra
|
/* The original count value accounts for the extra
|
||||||
|
@ -506,8 +513,8 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
if (flags & I2C_M_RD) {
|
if (flags & I2C_M_RD) {
|
||||||
bit_dbg(3, &i2c_adap->dev, "emitting repeated "
|
bit_dbg(3, &i2c_adap->dev,
|
||||||
"start condition\n");
|
"emitting repeated start condition\n");
|
||||||
i2c_repstart(adap);
|
i2c_repstart(adap);
|
||||||
/* okay, now switch into reading mode */
|
/* okay, now switch into reading mode */
|
||||||
addr |= 0x01;
|
addr |= 0x01;
|
||||||
|
@ -564,8 +571,8 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
|
||||||
}
|
}
|
||||||
ret = bit_doAddress(i2c_adap, pmsg);
|
ret = bit_doAddress(i2c_adap, pmsg);
|
||||||
if ((ret != 0) && !nak_ok) {
|
if ((ret != 0) && !nak_ok) {
|
||||||
bit_dbg(1, &i2c_adap->dev, "NAK from "
|
bit_dbg(1, &i2c_adap->dev,
|
||||||
"device addr 0x%02x msg #%d\n",
|
"NAK from device addr 0x%02x msg #%d\n",
|
||||||
msgs[i].addr, i);
|
msgs[i].addr, i);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
|
@ -708,7 +708,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
||||||
i2c_set_adapdata(adap, dev);
|
i2c_set_adapdata(adap, dev);
|
||||||
|
|
||||||
if (dev->pm_disabled) {
|
if (dev->pm_disabled) {
|
||||||
dev_pm_syscore_device(dev->dev, true);
|
|
||||||
irq_flags = IRQF_NO_SUSPEND;
|
irq_flags = IRQF_NO_SUSPEND;
|
||||||
} else {
|
} else {
|
||||||
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
|
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
|
||||||
|
|
|
@ -434,6 +434,9 @@ static int dw_i2c_plat_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (i_dev->pm_disabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
i_dev->disable(i_dev);
|
i_dev->disable(i_dev);
|
||||||
i2c_dw_prepare_clk(i_dev, false);
|
i2c_dw_prepare_clk(i_dev, false);
|
||||||
|
|
||||||
|
@ -444,7 +447,9 @@ static int dw_i2c_plat_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (!i_dev->pm_disabled)
|
||||||
i2c_dw_prepare_clk(i_dev, true);
|
i2c_dw_prepare_clk(i_dev, true);
|
||||||
|
|
||||||
i_dev->init(i_dev);
|
i_dev->init(i_dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1415,6 +1415,13 @@ static void i801_add_tco(struct i801_priv *priv)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
|
||||||
|
acpi_physical_address address)
|
||||||
|
{
|
||||||
|
return address >= priv->smba &&
|
||||||
|
address <= pci_resource_end(priv->pci_dev, SMBBAR);
|
||||||
|
}
|
||||||
|
|
||||||
static acpi_status
|
static acpi_status
|
||||||
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
|
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
|
||||||
u64 *value, void *handler_context, void *region_context)
|
u64 *value, void *handler_context, void *region_context)
|
||||||
|
@ -1430,7 +1437,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
|
||||||
*/
|
*/
|
||||||
mutex_lock(&priv->acpi_lock);
|
mutex_lock(&priv->acpi_lock);
|
||||||
|
|
||||||
if (!priv->acpi_reserved) {
|
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
|
||||||
priv->acpi_reserved = true;
|
priv->acpi_reserved = true;
|
||||||
|
|
||||||
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
|
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
|
||||||
|
|
|
@ -507,8 +507,6 @@ static void sh_mobile_i2c_dma_callback(void *data)
|
||||||
pd->pos = pd->msg->len;
|
pd->pos = pd->msg->len;
|
||||||
pd->stop_after_dma = true;
|
pd->stop_after_dma = true;
|
||||||
|
|
||||||
i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf);
|
|
||||||
|
|
||||||
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
|
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +600,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
|
||||||
dma_async_issue_pending(chan);
|
dma_async_issue_pending(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
||||||
bool do_init)
|
bool do_init)
|
||||||
{
|
{
|
||||||
if (do_init) {
|
if (do_init) {
|
||||||
|
@ -627,7 +625,6 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
||||||
|
|
||||||
/* Enable all interrupts to begin with */
|
/* Enable all interrupts to begin with */
|
||||||
iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int poll_dte(struct sh_mobile_i2c_data *pd)
|
static int poll_dte(struct sh_mobile_i2c_data *pd)
|
||||||
|
@ -698,9 +695,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||||
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
|
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
|
||||||
pd->stop_after_dma = false;
|
pd->stop_after_dma = false;
|
||||||
|
|
||||||
err = start_ch(pd, msg, do_start);
|
start_ch(pd, msg, do_start);
|
||||||
if (err)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (do_start)
|
if (do_start)
|
||||||
i2c_op(pd, OP_START, 0);
|
i2c_op(pd, OP_START, 0);
|
||||||
|
@ -709,6 +704,10 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||||
timeout = wait_event_timeout(pd->wait,
|
timeout = wait_event_timeout(pd->wait,
|
||||||
pd->sr & (ICSR_TACK | SW_DONE),
|
pd->sr & (ICSR_TACK | SW_DONE),
|
||||||
adapter->timeout);
|
adapter->timeout);
|
||||||
|
|
||||||
|
/* 'stop_after_dma' tells if DMA transfer was complete */
|
||||||
|
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
|
||||||
|
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
dev_err(pd->dev, "Transfer request timed out\n");
|
dev_err(pd->dev, "Transfer request timed out\n");
|
||||||
if (pd->dma_direction != DMA_NONE)
|
if (pd->dma_direction != DMA_NONE)
|
||||||
|
|
|
@ -2293,21 +2293,22 @@ u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold)
|
||||||
EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
|
EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
|
* i2c_put_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
|
||||||
* @msg: the message to be synced with
|
|
||||||
* @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL.
|
* @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL.
|
||||||
|
* @msg: the message which the buffer corresponds to
|
||||||
|
* @xferred: bool saying if the message was transferred
|
||||||
*/
|
*/
|
||||||
void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf)
|
void i2c_put_dma_safe_msg_buf(u8 *buf, struct i2c_msg *msg, bool xferred)
|
||||||
{
|
{
|
||||||
if (!buf || buf == msg->buf)
|
if (!buf || buf == msg->buf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (msg->flags & I2C_M_RD)
|
if (xferred && msg->flags & I2C_M_RD)
|
||||||
memcpy(msg->buf, buf, msg->len);
|
memcpy(msg->buf, buf, msg->len);
|
||||||
|
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf);
|
EXPORT_SYMBOL_GPL(i2c_put_dma_safe_msg_buf);
|
||||||
|
|
||||||
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||||
MODULE_DESCRIPTION("I2C-Bus main module");
|
MODULE_DESCRIPTION("I2C-Bus main module");
|
||||||
|
|
|
@ -855,7 +855,7 @@ static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);
|
u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);
|
||||||
void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf);
|
void i2c_put_dma_safe_msg_buf(u8 *buf, struct i2c_msg *msg, bool xferred);
|
||||||
|
|
||||||
int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
|
int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче