/* Module setup. */
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>");
MODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge");
MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17));
/* Default I2C speed to be set when a DS28E17 is detected. */ staticint i2c_speed = 100;
module_param_named(speed, i2c_speed, int, 0600);
MODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected");
/* Default I2C stretch value to be set when a DS28E17 is detected. */ staticchar i2c_stretch = 1;
module_param_named(stretch, i2c_stretch, byte, 0600);
MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected");
/* Now continusly check the busy flag sent by the DS28E17. */
checks = W1_F19_BUSY_CHECKS; while ((checks--) > 0) { /* Return success if the busy flag is cleared. */ if (w1_touch_bit(sl->master, 1) == 0) return0;
/* Wait one non-streched byte timeslot. */
udelay(timebases[data->speed]);
}
/* Return number of bytes written. */ return count;
}
/* Write data to I2C slave. */ staticint w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address, const u8 *buffer, size_t count, bool stop)
{ int result; int remaining = count; const u8 *p;
u8 command[2];
/* Check input. */ if (count == 0) return -EOPNOTSUPP;
/* Check whether we need multiple commands. */ if (count <= W1_F19_WRITE_DATA_LIMIT) { /* *Smalldataamount.Datacanbesentwith *asingleonewirecommand.
*/
/* Send all data to DS28E17. */
command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP
: W1_F19_WRITE_DATA_NO_STOP);
command[1] = i2c_address << 1;
result = __w1_f19_i2c_write(sl, command, 2, buffer, count);
} else { /* Large data amount. Data has to be sent in multiple chunks. */
/* Send first chunk to DS28E17. */
p = buffer;
command[0] = W1_F19_WRITE_DATA_NO_STOP;
command[1] = i2c_address << 1;
result = __w1_f19_i2c_write(sl, command, 2, p,
W1_F19_WRITE_DATA_LIMIT); if (result < 0) return result;
/* Resume to same DS28E17. */ if (w1_reset_resume_command(sl->master)) return -EIO;
/* Next data chunk. */
p += W1_F19_WRITE_DATA_LIMIT;
remaining -= W1_F19_WRITE_DATA_LIMIT;
while (remaining > W1_F19_WRITE_DATA_LIMIT) { /* Send intermediate chunk to DS28E17. */
command[0] = W1_F19_WRITE_DATA_ONLY;
result = __w1_f19_i2c_write(sl, command, 1, p,
W1_F19_WRITE_DATA_LIMIT); if (result < 0) return result;
/* Resume to same DS28E17. */ if (w1_reset_resume_command(sl->master)) return -EIO;
/* Next data chunk. */
p += W1_F19_WRITE_DATA_LIMIT;
remaining -= W1_F19_WRITE_DATA_LIMIT;
}
/* Send final chunk to DS28E17. */
command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP
: W1_F19_WRITE_DATA_ONLY);
result = __w1_f19_i2c_write(sl, command, 1, p, remaining);
}
return result;
}
/* Read data from I2C slave. */ staticint w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address,
u8 *buffer, size_t count)
{
u16 crc; int error;
u8 w1_buf[5];
/* Check input. */ if (count == 0) return -EOPNOTSUPP;
/* Read received I2C data from DS28E17. */ return w1_read_block(sl->master, rbuffer, rcount);
}
/* Do an I2C master transfer. */ staticint w1_f19_i2c_master_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{ struct w1_slave *sl = (struct w1_slave *) adapter->algo_data; int i = 0; int result = 0;
/* Select DS28E17. */ if (w1_reset_select_slave(sl)) {
i = -EIO; goto error;
}
/* Loop while there are still messages to transfer. */ while (i < num) { /* *Checkforspecialcase:Smallwritefollowed *byreadtosameI2Cdevice.
*/ if (i < (num-1)
&& msgs[i].addr == msgs[i+1].addr
&& !(msgs[i].flags & I2C_M_RD)
&& (msgs[i+1].flags & I2C_M_RD)
&& (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) { /* *TheDS28E17hasacombinedtransfer *forsmallwrite+read.
*/
result = w1_f19_i2c_write_read(sl, msgs[i].addr,
msgs[i].buf, msgs[i].len,
msgs[i+1].buf, msgs[i+1].len); if (result < 0) {
i = result; goto error;
}
/* *Checkifweshouldinterpretthereaddata *asalengthbyte.TheDS28E17unfortunately *hasnoreadwithoutstop,sowecanjustdo *anothersimplereadinthatcase.
*/ if (msgs[i+1].flags & I2C_M_RECV_LEN) {
result = w1_f19_i2c_read(sl, msgs[i+1].addr,
&(msgs[i+1].buf[1]), msgs[i+1].buf[0]); if (result < 0) {
i = result; goto error;
}
}
/* Eat up read message, too. */
i++;
} elseif (msgs[i].flags & I2C_M_RD) { /* Read transfer. */
result = w1_f19_i2c_read(sl, msgs[i].addr,
msgs[i].buf, msgs[i].len); if (result < 0) {
i = result; goto error;
}
/* *Checkifweshouldinterpretthereaddata *asalengthbyte.TheDS28E17unfortunately *hasnoreadwithoutstop,sowecanjustdo *anothersimplereadinthatcase.
*/ if (msgs[i].flags & I2C_M_RECV_LEN) {
result = w1_f19_i2c_read(sl,
msgs[i].addr,
&(msgs[i].buf[1]),
msgs[i].buf[0]); if (result < 0) {
i = result; goto error;
}
}
} else { /* *Writetransfer. *Stopconditiononlyforlast *transfer.
*/
result = w1_f19_i2c_write(sl,
msgs[i].addr,
msgs[i].buf,
msgs[i].len,
i == (num-1)); if (result < 0) {
i = result; goto error;
}
}
/* Next message. */
i++;
/* Are there still messages to send/receive? */ if (i < num) { /* Yes. Resume to same DS28E17. */ if (w1_reset_resume_command(sl->master)) {
i = -EIO; goto error;
}
}
}
error: /* End onewire transaction. */
mutex_unlock(&sl->master->bus_mutex);
/* Return number of messages processed or error. */ return i;
}
/* Allocate memory for slave specific data. */
data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
sl->family_data = data;
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.