linuxdebug/drivers/w1/slaves/w1_ds28e17.c

756 lines
18 KiB
C
Raw Permalink Normal View History

2024-07-16 15:50:57 +02:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds28e17.c - w1 family 19 (DS28E17) driver
*
* Copyright (c) 2016 Jan Kandziora <jjj@gmx.de>
*/
#include <linux/crc16.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#define CRC16_INIT 0
#include <linux/w1.h>
#define W1_FAMILY_DS28E17 0x19
/* 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. */
static int i2c_speed = 100;
module_param_named(speed, i2c_speed, int, (S_IRUSR | S_IWUSR));
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. */
static char i2c_stretch = 1;
module_param_named(stretch, i2c_stretch, byte, (S_IRUSR | S_IWUSR));
MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected");
/* DS28E17 device command codes. */
#define W1_F19_WRITE_DATA_WITH_STOP 0x4B
#define W1_F19_WRITE_DATA_NO_STOP 0x5A
#define W1_F19_WRITE_DATA_ONLY 0x69
#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78
#define W1_F19_READ_DATA_WITH_STOP 0x87
#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D
#define W1_F19_WRITE_CONFIGURATION 0xD2
#define W1_F19_READ_CONFIGURATION 0xE1
#define W1_F19_ENABLE_SLEEP_MODE 0x1E
#define W1_F19_READ_DEVICE_REVISION 0xC4
/* DS28E17 status bits */
#define W1_F19_STATUS_CRC 0x01
#define W1_F19_STATUS_ADDRESS 0x02
#define W1_F19_STATUS_START 0x08
/*
* Maximum number of I2C bytes to transfer within one CRC16 protected onewire
* command.
* */
#define W1_F19_WRITE_DATA_LIMIT 255
/* Maximum number of I2C bytes to read with one onewire command. */
#define W1_F19_READ_DATA_LIMIT 255
/* Constants for calculating the busy sleep. */
#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 }
#define W1_F19_BUSY_GRATUITY 1000
/* Number of checks for the busy flag before timeout. */
#define W1_F19_BUSY_CHECKS 1000
/* Slave specific data. */
struct w1_f19_data {
u8 speed;
u8 stretch;
struct i2c_adapter adapter;
};
/* Wait a while until the busy flag clears. */
static int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count)
{
const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES;
struct w1_f19_data *data = sl->family_data;
unsigned int checks;
/* Check the busy flag first in any case.*/
if (w1_touch_bit(sl->master, 1) == 0)
return 0;
/*
* Do a generously long sleep in the beginning,
* as we have to wait at least this time for all
* the I2C bytes at the given speed to be transferred.
*/
usleep_range(timebases[data->speed] * (data->stretch) * count,
timebases[data->speed] * (data->stretch) * count
+ W1_F19_BUSY_GRATUITY);
/* 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)
return 0;
/* Wait one non-streched byte timeslot. */
udelay(timebases[data->speed]);
}
/* Timeout. */
dev_warn(&sl->dev, "busy timeout\n");
return -ETIMEDOUT;
}
/* Utility function: result. */
static size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[])
{
/* Warnings. */
if (w1_buf[0] & W1_F19_STATUS_CRC)
dev_warn(&sl->dev, "crc16 mismatch\n");
if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
dev_warn(&sl->dev, "i2c device not responding\n");
if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0
&& w1_buf[1] != 0) {
dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n",
w1_buf[1]);
}
/* Check error conditions. */
if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
return -ENXIO;
if (w1_buf[0] & W1_F19_STATUS_START)
return -EAGAIN;
if (w1_buf[0] != 0 || w1_buf[1] != 0)
return -EIO;
/* All ok. */
return 0;
}
/* Utility function: write data to I2C slave, single chunk. */
static int __w1_f19_i2c_write(struct w1_slave *sl,
const u8 *command, size_t command_count,
const u8 *buffer, size_t count)
{
u16 crc;
int error;
u8 w1_buf[2];
/* Send command and I2C data to DS28E17. */
crc = crc16(CRC16_INIT, command, command_count);
w1_write_block(sl->master, command, command_count);
w1_buf[0] = count;
crc = crc16(crc, w1_buf, 1);
w1_write_8(sl->master, w1_buf[0]);
crc = crc16(crc, buffer, count);
w1_write_block(sl->master, buffer, count);
w1_buf[0] = ~(crc & 0xFF);
w1_buf[1] = ~((crc >> 8) & 0xFF);
w1_write_block(sl->master, w1_buf, 2);
/* Wait until busy flag clears (or timeout). */
if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
return -ETIMEDOUT;
/* Read status from DS28E17. */
w1_read_block(sl->master, w1_buf, 2);
/* Check error conditions. */
error = w1_f19_error(sl, w1_buf);
if (error < 0)
return error;
/* Return number of bytes written. */
return count;
}
/* Write data to I2C slave. */
static int 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) {
/*
* Small data amount. Data can be sent with
* a single onewire command.
*/
/* 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. */
static int 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;
/* Send command to DS28E17. */
w1_buf[0] = W1_F19_READ_DATA_WITH_STOP;
w1_buf[1] = i2c_address << 1 | 0x01;
w1_buf[2] = count;
crc = crc16(CRC16_INIT, w1_buf, 3);
w1_buf[3] = ~(crc & 0xFF);
w1_buf[4] = ~((crc >> 8) & 0xFF);
w1_write_block(sl->master, w1_buf, 5);
/* Wait until busy flag clears (or timeout). */
if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
return -ETIMEDOUT;
/* Read status from DS28E17. */
w1_buf[0] = w1_read_8(sl->master);
w1_buf[1] = 0;
/* Check error conditions. */
error = w1_f19_error(sl, w1_buf);
if (error < 0)
return error;
/* Read received I2C data from DS28E17. */
return w1_read_block(sl->master, buffer, count);
}
/* Write to, then read data from I2C slave. */
static int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address,
const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount)
{
u16 crc;
int error;
u8 w1_buf[3];
/* Check input. */
if (wcount == 0 || rcount == 0)
return -EOPNOTSUPP;
/* Send command and I2C data to DS28E17. */
w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP;
w1_buf[1] = i2c_address << 1;
w1_buf[2] = wcount;
crc = crc16(CRC16_INIT, w1_buf, 3);
w1_write_block(sl->master, w1_buf, 3);
crc = crc16(crc, wbuffer, wcount);
w1_write_block(sl->master, wbuffer, wcount);
w1_buf[0] = rcount;
crc = crc16(crc, w1_buf, 1);
w1_buf[1] = ~(crc & 0xFF);
w1_buf[2] = ~((crc >> 8) & 0xFF);
w1_write_block(sl->master, w1_buf, 3);
/* Wait until busy flag clears (or timeout). */
if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0)
return -ETIMEDOUT;
/* Read status from DS28E17. */
w1_read_block(sl->master, w1_buf, 2);
/* Check error conditions. */
error = w1_f19_error(sl, w1_buf);
if (error < 0)
return error;
/* Read received I2C data from DS28E17. */
return w1_read_block(sl->master, rbuffer, rcount);
}
/* Do an I2C master transfer. */
static int 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;
/* Start onewire transaction. */
mutex_lock(&sl->master->bus_mutex);
/* Select DS28E17. */
if (w1_reset_select_slave(sl)) {
i = -EIO;
goto error;
}
/* Loop while there are still messages to transfer. */
while (i < num) {
/*
* Check for special case: Small write followed
* by read to same I2C device.
*/
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)) {
/*
* The DS28E17 has a combined transfer
* for small write+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;
}
/*
* Check if we should interpret the read data
* as a length byte. The DS28E17 unfortunately
* has no read without stop, so we can just do
* another simple read in that case.
*/
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++;
} else if (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;
}
/*
* Check if we should interpret the read data
* as a length byte. The DS28E17 unfortunately
* has no read without stop, so we can just do
* another simple read in that case.
*/
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 {
/*
* Write transfer.
* Stop condition only for last
* 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;
}
/* Get I2C adapter functionality. */
static u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter)
{
/*
* Plain I2C functions only.
* SMBus is emulated by the kernel's I2C layer.
* No "I2C_FUNC_SMBUS_QUICK"
* No "I2C_FUNC_SMBUS_READ_BLOCK_DATA"
* No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL"
*/
return I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_PROC_CALL |
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK |
I2C_FUNC_SMBUS_PEC;
}
/* I2C adapter quirks. */
static const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = {
.max_read_len = W1_F19_READ_DATA_LIMIT,
};
/* I2C algorithm. */
static const struct i2c_algorithm w1_f19_i2c_algorithm = {
.master_xfer = w1_f19_i2c_master_transfer,
.functionality = w1_f19_i2c_functionality,
};
/* Read I2C speed from DS28E17. */
static int w1_f19_get_i2c_speed(struct w1_slave *sl)
{
struct w1_f19_data *data = sl->family_data;
int result = -EIO;
/* Start onewire transaction. */
mutex_lock(&sl->master->bus_mutex);
/* Select slave. */
if (w1_reset_select_slave(sl))
goto error;
/* Read slave configuration byte. */
w1_write_8(sl->master, W1_F19_READ_CONFIGURATION);
result = w1_read_8(sl->master);
if (result < 0 || result > 2) {
result = -EIO;
goto error;
}
/* Update speed in slave specific data. */
data->speed = result;
error:
/* End onewire transaction. */
mutex_unlock(&sl->master->bus_mutex);
return result;
}
/* Set I2C speed on DS28E17. */
static int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
{
struct w1_f19_data *data = sl->family_data;
const int i2c_speeds[3] = { 100, 400, 900 };
u8 w1_buf[2];
/* Select slave. */
if (w1_reset_select_slave(sl))
return -EIO;
w1_buf[0] = W1_F19_WRITE_CONFIGURATION;
w1_buf[1] = speed;
w1_write_block(sl->master, w1_buf, 2);
/* Update speed in slave specific data. */
data->speed = speed;
dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]);
return 0;
}
static int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
{
int result;
/* Start onewire transaction. */
mutex_lock(&sl->master->bus_mutex);
/* Set I2C speed on DS28E17. */
result = __w1_f19_set_i2c_speed(sl, speed);
/* End onewire transaction. */
mutex_unlock(&sl->master->bus_mutex);
return result;
}
/* Sysfs attributes. */
/* I2C speed attribute for a single chip. */
static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
int result;
/* Read current speed from slave. Updates data->speed. */
result = w1_f19_get_i2c_speed(sl);
if (result < 0)
return result;
/* Return current speed value. */
return sprintf(buf, "%d\n", result);
}
static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
int error;
/* Valid values are: "100", "400", "900" */
if (count < 3 || count > 4 || !buf)
return -EINVAL;
if (count == 4 && buf[3] != '\n')
return -EINVAL;
if (buf[1] != '0' || buf[2] != '0')
return -EINVAL;
/* Set speed on slave. */
switch (buf[0]) {
case '1':
error = w1_f19_set_i2c_speed(sl, 0);
break;
case '4':
error = w1_f19_set_i2c_speed(sl, 1);
break;
case '9':
error = w1_f19_set_i2c_speed(sl, 2);
break;
default:
return -EINVAL;
}
if (error < 0)
return error;
/* Return bytes written. */
return count;
}
static DEVICE_ATTR_RW(speed);
/* Busy stretch attribute for a single chip. */
static ssize_t stretch_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
struct w1_f19_data *data = sl->family_data;
/* Return current stretch value. */
return sprintf(buf, "%d\n", data->stretch);
}
static ssize_t stretch_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
struct w1_f19_data *data = sl->family_data;
/* Valid values are '1' to '9' */
if (count < 1 || count > 2 || !buf)
return -EINVAL;
if (count == 2 && buf[1] != '\n')
return -EINVAL;
if (buf[0] < '1' || buf[0] > '9')
return -EINVAL;
/* Set busy stretch value. */
data->stretch = buf[0] & 0x0F;
/* Return bytes written. */
return count;
}
static DEVICE_ATTR_RW(stretch);
/* All attributes. */
static struct attribute *w1_f19_attrs[] = {
&dev_attr_speed.attr,
&dev_attr_stretch.attr,
NULL,
};
static const struct attribute_group w1_f19_group = {
.attrs = w1_f19_attrs,
};
static const struct attribute_group *w1_f19_groups[] = {
&w1_f19_group,
NULL,
};
/* Slave add and remove functions. */
static int w1_f19_add_slave(struct w1_slave *sl)
{
struct w1_f19_data *data = NULL;
/* Allocate memory for slave specific data. */
data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
sl->family_data = data;
/* Setup default I2C speed on slave. */
switch (i2c_speed) {
case 100:
__w1_f19_set_i2c_speed(sl, 0);
break;
case 400:
__w1_f19_set_i2c_speed(sl, 1);
break;
case 900:
__w1_f19_set_i2c_speed(sl, 2);
break;
default:
/*
* A i2c_speed module parameter of anything else
* than 100, 400, 900 means not to touch the
* speed of the DS28E17.
* We assume 400kBaud, the power-on value.
*/
data->speed = 1;
}
/*
* Setup default busy stretch
* configuration for the DS28E17.
*/
data->stretch = i2c_stretch;
/* Setup I2C adapter. */
data->adapter.owner = THIS_MODULE;
data->adapter.algo = &w1_f19_i2c_algorithm;
data->adapter.algo_data = sl;
strcpy(data->adapter.name, "w1-");
strcat(data->adapter.name, sl->name);
data->adapter.dev.parent = &sl->dev;
data->adapter.quirks = &w1_f19_i2c_adapter_quirks;
return i2c_add_adapter(&data->adapter);
}
static void w1_f19_remove_slave(struct w1_slave *sl)
{
struct w1_f19_data *family_data = sl->family_data;
/* Delete I2C adapter. */
i2c_del_adapter(&family_data->adapter);
/* Free slave specific data. */
devm_kfree(&sl->dev, family_data);
sl->family_data = NULL;
}
/* Declarations within the w1 subsystem. */
static const struct w1_family_ops w1_f19_fops = {
.add_slave = w1_f19_add_slave,
.remove_slave = w1_f19_remove_slave,
.groups = w1_f19_groups,
};
static struct w1_family w1_family_19 = {
.fid = W1_FAMILY_DS28E17,
.fops = &w1_f19_fops,
};
module_w1_family(w1_family_19);