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.
-In any case, a buffer obtained from above needs to be released. It ensures data
-is copied back to the message and a potentially used bounce buffer is freed::
+In any case, a buffer obtained from above needs to be released. Another helper
+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
allocate a new bounce buffer. If you want a more sophisticated handling (e.g.
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
- pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
- "high\n", jiffies - start);
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go high\n",
+ jiffies - start);
#endif
done:
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);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_outb: 0x%02x, timeout at bit #%d\n",
+ (int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
}
sdahi(adap);
if (sclhi(adap) < 0) { /* timeout */
- bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
- "timeout at ack\n", (int)c);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
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);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_inb: timeout at bit #%d\n",
+ 7 - i);
return -ETIMEDOUT;
}
indata *= 2;
goto bailout;
}
if (!scl) {
- printk(KERN_WARNING "%s: SCL unexpected low "
- "while pulling SDA low!\n", name);
+ printk(KERN_WARNING
+ "%s: SCL unexpected low while pulling SDA low!\n",
+ name);
goto bailout;
}
goto bailout;
}
if (!scl) {
- printk(KERN_WARNING "%s: SCL unexpected low "
- "while pulling SDA high!\n", name);
+ printk(KERN_WARNING
+ "%s: SCL unexpected low while pulling SDA high!\n",
+ name);
goto bailout;
}
goto bailout;
}
if (!sda) {
- printk(KERN_WARNING "%s: SDA unexpected low "
- "while pulling SCL low!\n", name);
+ printk(KERN_WARNING
+ "%s: SDA unexpected low while pulling SCL low!\n",
+ name);
goto bailout;
}
goto bailout;
}
if (!sda) {
- printk(KERN_WARNING "%s: SDA unexpected low "
- "while pulling SCL high!\n", name);
+ printk(KERN_WARNING
+ "%s: SDA unexpected low while pulling SCL high!\n",
+ name);
goto bailout;
}
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,
+ 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;
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);
+ dev_err(&i2c_adap->dev,
+ "readbytes: invalid block length (%d)\n",
+ inval);
return -EPROTO;
}
/* The original count value accounts for the extra
return -ENXIO;
}
if (flags & I2C_M_RD) {
- bit_dbg(3, &i2c_adap->dev, "emitting repeated "
- "start condition\n");
+ bit_dbg(3, &i2c_adap->dev,
+ "emitting repeated start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
}
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",
+ bit_dbg(1, &i2c_adap->dev,
+ "NAK from device addr 0x%02x msg #%d\n",
msgs[i].addr, i);
goto bailout;
}
i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) {
- dev_pm_syscore_device(dev->dev, true);
irq_flags = IRQF_NO_SUSPEND;
} else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
+ if (i_dev->pm_disabled)
+ return 0;
+
i_dev->disable(i_dev);
i2c_dw_prepare_clk(i_dev, false);
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
- i2c_dw_prepare_clk(i_dev, true);
+ if (!i_dev->pm_disabled)
+ i2c_dw_prepare_clk(i_dev, true);
+
i_dev->init(i_dev);
return 0;
}
#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
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
u64 *value, void *handler_context, void *region_context)
*/
mutex_lock(&priv->acpi_lock);
- if (!priv->acpi_reserved) {
+ if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true;
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
pd->pos = pd->msg->len;
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);
}
dma_async_issue_pending(chan);
}
-static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
- bool do_init)
+static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
+ bool do_init)
{
if (do_init) {
/* Initialize channel registers */
/* Enable all interrupts to begin with */
iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
- return 0;
}
static int poll_dte(struct sh_mobile_i2c_data *pd)
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
pd->stop_after_dma = false;
- err = start_ch(pd, msg, do_start);
- if (err)
- break;
+ start_ch(pd, msg, do_start);
if (do_start)
i2c_op(pd, OP_START, 0);
timeout = wait_event_timeout(pd->wait,
pd->sr & (ICSR_TACK | SW_DONE),
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) {
dev_err(pd->dev, "Transfer request timed out\n");
if (pd->dma_direction != DMA_NONE)
EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
/**
- * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
- * @msg: the message to be synced with
+ * i2c_put_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
* @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)
return;
- if (msg->flags & I2C_M_RD)
+ if (xferred && msg->flags & I2C_M_RD)
memcpy(msg->buf, buf, msg->len);
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_DESCRIPTION("I2C-Bus main module");
}
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);
/**