/* * Wait for one or more bits in flag change. * HDQ_FLAG_SET: wait until any bit in the flag is set. * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared. * return 0 on success and -ETIMEDOUT in the case of timeout.
*/ staticint hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
u8 flag, u8 flag_set, u8 *status)
{ int ret = 0; unsignedlong timeout = jiffies + OMAP_HDQ_TIMEOUT;
if (flag_set == OMAP_HDQ_FLAG_CLEAR) { /* wait for the flag clear */ while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
&& time_before(jiffies, timeout)) {
schedule_timeout_uninterruptible(1);
} if (*status & flag)
ret = -ETIMEDOUT;
} elseif (flag_set == OMAP_HDQ_FLAG_SET) { /* wait for the flag set */ while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
&& time_before(jiffies, timeout)) {
schedule_timeout_uninterruptible(1);
} if (!(*status & flag))
ret = -ETIMEDOUT;
} else return -EINVAL;
return ret;
}
/* Clear saved irqstatus after using an interrupt */ static u8 hdq_reset_irqstatus(struct hdq_data *hdq_data, u8 bits)
{ unsignedlong irqflags;
u8 status;
spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
status = hdq_data->hdq_irqstatus; /* this is a read-modify-write */
hdq_data->hdq_irqstatus &= ~bits;
spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
return status;
}
/* write out a byte and fill *status with HDQ_INT_STATUS */ staticint hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
{ int ret;
u8 tmp_status;
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); if (ret < 0) {
ret = -EINTR; goto rtn;
}
if (hdq_data->hdq_irqstatus)
dev_err(hdq_data->dev, "TX irqstatus not cleared (%02x)\n",
hdq_data->hdq_irqstatus);
*status = 0;
hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
/* set the GO bit */
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO); /* wait for the TXCOMPLETE bit */
ret = wait_event_timeout(hdq_wait_queue,
(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TXCOMPLETE),
OMAP_HDQ_TIMEOUT);
*status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE); if (ret == 0) {
dev_dbg(hdq_data->dev, "TX wait elapsed\n");
ret = -ETIMEDOUT; goto out;
}
/* wait for the GO bit return to zero */
ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
OMAP_HDQ_CTRL_STATUS_GO,
OMAP_HDQ_FLAG_CLEAR, &tmp_status); if (ret) {
dev_dbg(hdq_data->dev, "timeout waiting GO bit" " return to zero, %x\n", tmp_status);
}
if (hdq_data->hdq_irqstatus &
(OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
| OMAP_HDQ_INT_STATUS_TIMEOUT)) { /* wake up sleeping process */
wake_up(&hdq_wait_queue);
}
if (w1_id)
module_id = w1_id; else
module_id = 0x1;
rn_le = cpu_to_le64(module_id); /* * HDQ might not obey truly the 1-wire spec. * So calculate CRC based on module parameter.
*/
cs = w1_calc_crc8((u8 *)&rn_le, 7);
id = (cs << 56) | module_id;
slave_found(master_dev, id);
}
/* Issue break pulse to the device */ staticint omap_hdq_break(struct hdq_data *hdq_data)
{ int ret = 0;
u8 tmp_status;
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); if (ret < 0) {
dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
ret = -EINTR; goto rtn;
}
if (hdq_data->hdq_irqstatus)
dev_err(hdq_data->dev, "break irqstatus not cleared (%02x)\n",
hdq_data->hdq_irqstatus);
/* set the INIT and GO bit */
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
OMAP_HDQ_CTRL_STATUS_GO);
/* wait for the TIMEOUT bit */
ret = wait_event_timeout(hdq_wait_queue,
(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TIMEOUT),
OMAP_HDQ_TIMEOUT);
tmp_status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TIMEOUT); if (ret == 0) {
dev_dbg(hdq_data->dev, "break wait elapsed\n");
ret = -EINTR; goto out;
}
/* check irqstatus */ if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x\n",
tmp_status);
ret = -ETIMEDOUT; goto out;
}
/* * check for the presence detect bit to get * set to show that the slave is responding
*/ if (!(hdq_reg_in(hdq_data, OMAP_HDQ_CTRL_STATUS) &
OMAP_HDQ_CTRL_STATUS_PRESENCE)) {
dev_dbg(hdq_data->dev, "Presence bit not set\n");
ret = -ETIMEDOUT; goto out;
}
/* * wait for both INIT and GO bits rerurn to zero. * zero wait time expected for interrupt mode.
*/
ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
&tmp_status); if (ret)
dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits" " return to zero, %x\n", tmp_status);
if (id_bit && comp_bit) {
ret = 0x03; /* no slaves responded */ goto out;
} if (!id_bit && !comp_bit) { /* Both bits are valid, take the direction given */
ret = bdir ? 0x04 : 0;
} else { /* Only one bit is valid, take that direction */
bdir = id_bit;
ret = id_bit ? 0x05 : 0x02;
}
/* write bdir bit */
hdq_reg_out(_hdq, OMAP_HDQ_TX_DATA, bdir);
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, ctrl, mask);
err = wait_event_timeout(hdq_wait_queue,
(hdq_data->hdq_irqstatus
& OMAP_HDQ_INT_STATUS_TXCOMPLETE),
OMAP_HDQ_TIMEOUT); /* Must clear irqstatus for another TXCOMPLETE interrupt */
hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE);
/* Write a byte of data to the device */ staticvoid omap_w1_write_byte(void *_hdq, u8 byte)
{ struct hdq_data *hdq_data = _hdq; int ret;
u8 status;
ret = pm_runtime_get_sync(hdq_data->dev); if (ret < 0) {
pm_runtime_put_noidle(hdq_data->dev);
return;
}
/* * We need to reset the slave before * issuing the SKIP ROM command, else * the slave will not work.
*/ if (byte == W1_SKIP_ROM)
omap_hdq_break(hdq_data);
ret = hdq_write_byte(hdq_data, byte, &status); if (ret < 0) {
dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status); goto out_err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.