Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jan Kandziora | 3048 | 99.93% | 1 | 50.00% |
Thomas Gleixner | 2 | 0.07% | 1 | 50.00% |
Total | 3050 | 2 |
// 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 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 init and remove functions. */ static int __init w1_f19_init(void) { return w1_register_family(&w1_family_19); } static void __exit w1_f19_fini(void) { w1_unregister_family(&w1_family_19); } module_init(w1_f19_init); module_exit(w1_f19_fini);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1