| // 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); |
| |