18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * w1_ds28e17.c - w1 family 19 (DS28E17) driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Jan Kandziora <jjj@gmx.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/crc16.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/types.h> 178c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define CRC16_INIT 0 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/w1.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define W1_FAMILY_DS28E17 0x19 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Module setup. */ 268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>"); 288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge"); 298c2ecf20Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17)); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Default I2C speed to be set when a DS28E17 is detected. */ 338c2ecf20Sopenharmony_cistatic int i2c_speed = 100; 348c2ecf20Sopenharmony_cimodule_param_named(speed, i2c_speed, int, (S_IRUSR | S_IWUSR)); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Default I2C stretch value to be set when a DS28E17 is detected. */ 388c2ecf20Sopenharmony_cistatic char i2c_stretch = 1; 398c2ecf20Sopenharmony_cimodule_param_named(stretch, i2c_stretch, byte, (S_IRUSR | S_IWUSR)); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* DS28E17 device command codes. */ 438c2ecf20Sopenharmony_ci#define W1_F19_WRITE_DATA_WITH_STOP 0x4B 448c2ecf20Sopenharmony_ci#define W1_F19_WRITE_DATA_NO_STOP 0x5A 458c2ecf20Sopenharmony_ci#define W1_F19_WRITE_DATA_ONLY 0x69 468c2ecf20Sopenharmony_ci#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78 478c2ecf20Sopenharmony_ci#define W1_F19_READ_DATA_WITH_STOP 0x87 488c2ecf20Sopenharmony_ci#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D 498c2ecf20Sopenharmony_ci#define W1_F19_WRITE_CONFIGURATION 0xD2 508c2ecf20Sopenharmony_ci#define W1_F19_READ_CONFIGURATION 0xE1 518c2ecf20Sopenharmony_ci#define W1_F19_ENABLE_SLEEP_MODE 0x1E 528c2ecf20Sopenharmony_ci#define W1_F19_READ_DEVICE_REVISION 0xC4 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* DS28E17 status bits */ 558c2ecf20Sopenharmony_ci#define W1_F19_STATUS_CRC 0x01 568c2ecf20Sopenharmony_ci#define W1_F19_STATUS_ADDRESS 0x02 578c2ecf20Sopenharmony_ci#define W1_F19_STATUS_START 0x08 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * Maximum number of I2C bytes to transfer within one CRC16 protected onewire 618c2ecf20Sopenharmony_ci * command. 628c2ecf20Sopenharmony_ci * */ 638c2ecf20Sopenharmony_ci#define W1_F19_WRITE_DATA_LIMIT 255 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Maximum number of I2C bytes to read with one onewire command. */ 668c2ecf20Sopenharmony_ci#define W1_F19_READ_DATA_LIMIT 255 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Constants for calculating the busy sleep. */ 698c2ecf20Sopenharmony_ci#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 } 708c2ecf20Sopenharmony_ci#define W1_F19_BUSY_GRATUITY 1000 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Number of checks for the busy flag before timeout. */ 738c2ecf20Sopenharmony_ci#define W1_F19_BUSY_CHECKS 1000 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Slave specific data. */ 778c2ecf20Sopenharmony_cistruct w1_f19_data { 788c2ecf20Sopenharmony_ci u8 speed; 798c2ecf20Sopenharmony_ci u8 stretch; 808c2ecf20Sopenharmony_ci struct i2c_adapter adapter; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Wait a while until the busy flag clears. */ 858c2ecf20Sopenharmony_cistatic int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES; 888c2ecf20Sopenharmony_ci struct w1_f19_data *data = sl->family_data; 898c2ecf20Sopenharmony_ci unsigned int checks; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Check the busy flag first in any case.*/ 928c2ecf20Sopenharmony_ci if (w1_touch_bit(sl->master, 1) == 0) 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * Do a generously long sleep in the beginning, 978c2ecf20Sopenharmony_ci * as we have to wait at least this time for all 988c2ecf20Sopenharmony_ci * the I2C bytes at the given speed to be transferred. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci usleep_range(timebases[data->speed] * (data->stretch) * count, 1018c2ecf20Sopenharmony_ci timebases[data->speed] * (data->stretch) * count 1028c2ecf20Sopenharmony_ci + W1_F19_BUSY_GRATUITY); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Now continusly check the busy flag sent by the DS28E17. */ 1058c2ecf20Sopenharmony_ci checks = W1_F19_BUSY_CHECKS; 1068c2ecf20Sopenharmony_ci while ((checks--) > 0) { 1078c2ecf20Sopenharmony_ci /* Return success if the busy flag is cleared. */ 1088c2ecf20Sopenharmony_ci if (w1_touch_bit(sl->master, 1) == 0) 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Wait one non-streched byte timeslot. */ 1128c2ecf20Sopenharmony_ci udelay(timebases[data->speed]); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Timeout. */ 1168c2ecf20Sopenharmony_ci dev_warn(&sl->dev, "busy timeout\n"); 1178c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* Utility function: result. */ 1228c2ecf20Sopenharmony_cistatic size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[]) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci /* Warnings. */ 1258c2ecf20Sopenharmony_ci if (w1_buf[0] & W1_F19_STATUS_CRC) 1268c2ecf20Sopenharmony_ci dev_warn(&sl->dev, "crc16 mismatch\n"); 1278c2ecf20Sopenharmony_ci if (w1_buf[0] & W1_F19_STATUS_ADDRESS) 1288c2ecf20Sopenharmony_ci dev_warn(&sl->dev, "i2c device not responding\n"); 1298c2ecf20Sopenharmony_ci if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0 1308c2ecf20Sopenharmony_ci && w1_buf[1] != 0) { 1318c2ecf20Sopenharmony_ci dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n", 1328c2ecf20Sopenharmony_ci w1_buf[1]); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Check error conditions. */ 1368c2ecf20Sopenharmony_ci if (w1_buf[0] & W1_F19_STATUS_ADDRESS) 1378c2ecf20Sopenharmony_ci return -ENXIO; 1388c2ecf20Sopenharmony_ci if (w1_buf[0] & W1_F19_STATUS_START) 1398c2ecf20Sopenharmony_ci return -EAGAIN; 1408c2ecf20Sopenharmony_ci if (w1_buf[0] != 0 || w1_buf[1] != 0) 1418c2ecf20Sopenharmony_ci return -EIO; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* All ok. */ 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* Utility function: write data to I2C slave, single chunk. */ 1498c2ecf20Sopenharmony_cistatic int __w1_f19_i2c_write(struct w1_slave *sl, 1508c2ecf20Sopenharmony_ci const u8 *command, size_t command_count, 1518c2ecf20Sopenharmony_ci const u8 *buffer, size_t count) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci u16 crc; 1548c2ecf20Sopenharmony_ci int error; 1558c2ecf20Sopenharmony_ci u8 w1_buf[2]; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Send command and I2C data to DS28E17. */ 1588c2ecf20Sopenharmony_ci crc = crc16(CRC16_INIT, command, command_count); 1598c2ecf20Sopenharmony_ci w1_write_block(sl->master, command, command_count); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci w1_buf[0] = count; 1628c2ecf20Sopenharmony_ci crc = crc16(crc, w1_buf, 1); 1638c2ecf20Sopenharmony_ci w1_write_8(sl->master, w1_buf[0]); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci crc = crc16(crc, buffer, count); 1668c2ecf20Sopenharmony_ci w1_write_block(sl->master, buffer, count); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci w1_buf[0] = ~(crc & 0xFF); 1698c2ecf20Sopenharmony_ci w1_buf[1] = ~((crc >> 8) & 0xFF); 1708c2ecf20Sopenharmony_ci w1_write_block(sl->master, w1_buf, 2); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Wait until busy flag clears (or timeout). */ 1738c2ecf20Sopenharmony_ci if (w1_f19_i2c_busy_wait(sl, count + 1) < 0) 1748c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* Read status from DS28E17. */ 1778c2ecf20Sopenharmony_ci w1_read_block(sl->master, w1_buf, 2); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Check error conditions. */ 1808c2ecf20Sopenharmony_ci error = w1_f19_error(sl, w1_buf); 1818c2ecf20Sopenharmony_ci if (error < 0) 1828c2ecf20Sopenharmony_ci return error; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Return number of bytes written. */ 1858c2ecf20Sopenharmony_ci return count; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* Write data to I2C slave. */ 1908c2ecf20Sopenharmony_cistatic int w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address, 1918c2ecf20Sopenharmony_ci const u8 *buffer, size_t count, bool stop) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int result; 1948c2ecf20Sopenharmony_ci int remaining = count; 1958c2ecf20Sopenharmony_ci const u8 *p; 1968c2ecf20Sopenharmony_ci u8 command[2]; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Check input. */ 1998c2ecf20Sopenharmony_ci if (count == 0) 2008c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Check whether we need multiple commands. */ 2038c2ecf20Sopenharmony_ci if (count <= W1_F19_WRITE_DATA_LIMIT) { 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * Small data amount. Data can be sent with 2068c2ecf20Sopenharmony_ci * a single onewire command. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Send all data to DS28E17. */ 2108c2ecf20Sopenharmony_ci command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP 2118c2ecf20Sopenharmony_ci : W1_F19_WRITE_DATA_NO_STOP); 2128c2ecf20Sopenharmony_ci command[1] = i2c_address << 1; 2138c2ecf20Sopenharmony_ci result = __w1_f19_i2c_write(sl, command, 2, buffer, count); 2148c2ecf20Sopenharmony_ci } else { 2158c2ecf20Sopenharmony_ci /* Large data amount. Data has to be sent in multiple chunks. */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Send first chunk to DS28E17. */ 2188c2ecf20Sopenharmony_ci p = buffer; 2198c2ecf20Sopenharmony_ci command[0] = W1_F19_WRITE_DATA_NO_STOP; 2208c2ecf20Sopenharmony_ci command[1] = i2c_address << 1; 2218c2ecf20Sopenharmony_ci result = __w1_f19_i2c_write(sl, command, 2, p, 2228c2ecf20Sopenharmony_ci W1_F19_WRITE_DATA_LIMIT); 2238c2ecf20Sopenharmony_ci if (result < 0) 2248c2ecf20Sopenharmony_ci return result; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Resume to same DS28E17. */ 2278c2ecf20Sopenharmony_ci if (w1_reset_resume_command(sl->master)) 2288c2ecf20Sopenharmony_ci return -EIO; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Next data chunk. */ 2318c2ecf20Sopenharmony_ci p += W1_F19_WRITE_DATA_LIMIT; 2328c2ecf20Sopenharmony_ci remaining -= W1_F19_WRITE_DATA_LIMIT; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci while (remaining > W1_F19_WRITE_DATA_LIMIT) { 2358c2ecf20Sopenharmony_ci /* Send intermediate chunk to DS28E17. */ 2368c2ecf20Sopenharmony_ci command[0] = W1_F19_WRITE_DATA_ONLY; 2378c2ecf20Sopenharmony_ci result = __w1_f19_i2c_write(sl, command, 1, p, 2388c2ecf20Sopenharmony_ci W1_F19_WRITE_DATA_LIMIT); 2398c2ecf20Sopenharmony_ci if (result < 0) 2408c2ecf20Sopenharmony_ci return result; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Resume to same DS28E17. */ 2438c2ecf20Sopenharmony_ci if (w1_reset_resume_command(sl->master)) 2448c2ecf20Sopenharmony_ci return -EIO; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Next data chunk. */ 2478c2ecf20Sopenharmony_ci p += W1_F19_WRITE_DATA_LIMIT; 2488c2ecf20Sopenharmony_ci remaining -= W1_F19_WRITE_DATA_LIMIT; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Send final chunk to DS28E17. */ 2528c2ecf20Sopenharmony_ci command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP 2538c2ecf20Sopenharmony_ci : W1_F19_WRITE_DATA_ONLY); 2548c2ecf20Sopenharmony_ci result = __w1_f19_i2c_write(sl, command, 1, p, remaining); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return result; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* Read data from I2C slave. */ 2628c2ecf20Sopenharmony_cistatic int w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address, 2638c2ecf20Sopenharmony_ci u8 *buffer, size_t count) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci u16 crc; 2668c2ecf20Sopenharmony_ci int error; 2678c2ecf20Sopenharmony_ci u8 w1_buf[5]; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Check input. */ 2708c2ecf20Sopenharmony_ci if (count == 0) 2718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Send command to DS28E17. */ 2748c2ecf20Sopenharmony_ci w1_buf[0] = W1_F19_READ_DATA_WITH_STOP; 2758c2ecf20Sopenharmony_ci w1_buf[1] = i2c_address << 1 | 0x01; 2768c2ecf20Sopenharmony_ci w1_buf[2] = count; 2778c2ecf20Sopenharmony_ci crc = crc16(CRC16_INIT, w1_buf, 3); 2788c2ecf20Sopenharmony_ci w1_buf[3] = ~(crc & 0xFF); 2798c2ecf20Sopenharmony_ci w1_buf[4] = ~((crc >> 8) & 0xFF); 2808c2ecf20Sopenharmony_ci w1_write_block(sl->master, w1_buf, 5); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Wait until busy flag clears (or timeout). */ 2838c2ecf20Sopenharmony_ci if (w1_f19_i2c_busy_wait(sl, count + 1) < 0) 2848c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Read status from DS28E17. */ 2878c2ecf20Sopenharmony_ci w1_buf[0] = w1_read_8(sl->master); 2888c2ecf20Sopenharmony_ci w1_buf[1] = 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Check error conditions. */ 2918c2ecf20Sopenharmony_ci error = w1_f19_error(sl, w1_buf); 2928c2ecf20Sopenharmony_ci if (error < 0) 2938c2ecf20Sopenharmony_ci return error; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Read received I2C data from DS28E17. */ 2968c2ecf20Sopenharmony_ci return w1_read_block(sl->master, buffer, count); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* Write to, then read data from I2C slave. */ 3018c2ecf20Sopenharmony_cistatic int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address, 3028c2ecf20Sopenharmony_ci const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci u16 crc; 3058c2ecf20Sopenharmony_ci int error; 3068c2ecf20Sopenharmony_ci u8 w1_buf[3]; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Check input. */ 3098c2ecf20Sopenharmony_ci if (wcount == 0 || rcount == 0) 3108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Send command and I2C data to DS28E17. */ 3138c2ecf20Sopenharmony_ci w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP; 3148c2ecf20Sopenharmony_ci w1_buf[1] = i2c_address << 1; 3158c2ecf20Sopenharmony_ci w1_buf[2] = wcount; 3168c2ecf20Sopenharmony_ci crc = crc16(CRC16_INIT, w1_buf, 3); 3178c2ecf20Sopenharmony_ci w1_write_block(sl->master, w1_buf, 3); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci crc = crc16(crc, wbuffer, wcount); 3208c2ecf20Sopenharmony_ci w1_write_block(sl->master, wbuffer, wcount); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci w1_buf[0] = rcount; 3238c2ecf20Sopenharmony_ci crc = crc16(crc, w1_buf, 1); 3248c2ecf20Sopenharmony_ci w1_buf[1] = ~(crc & 0xFF); 3258c2ecf20Sopenharmony_ci w1_buf[2] = ~((crc >> 8) & 0xFF); 3268c2ecf20Sopenharmony_ci w1_write_block(sl->master, w1_buf, 3); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Wait until busy flag clears (or timeout). */ 3298c2ecf20Sopenharmony_ci if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0) 3308c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Read status from DS28E17. */ 3338c2ecf20Sopenharmony_ci w1_read_block(sl->master, w1_buf, 2); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Check error conditions. */ 3368c2ecf20Sopenharmony_ci error = w1_f19_error(sl, w1_buf); 3378c2ecf20Sopenharmony_ci if (error < 0) 3388c2ecf20Sopenharmony_ci return error; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Read received I2C data from DS28E17. */ 3418c2ecf20Sopenharmony_ci return w1_read_block(sl->master, rbuffer, rcount); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* Do an I2C master transfer. */ 3468c2ecf20Sopenharmony_cistatic int w1_f19_i2c_master_transfer(struct i2c_adapter *adapter, 3478c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct w1_slave *sl = (struct w1_slave *) adapter->algo_data; 3508c2ecf20Sopenharmony_ci int i = 0; 3518c2ecf20Sopenharmony_ci int result = 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Start onewire transaction. */ 3548c2ecf20Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Select DS28E17. */ 3578c2ecf20Sopenharmony_ci if (w1_reset_select_slave(sl)) { 3588c2ecf20Sopenharmony_ci i = -EIO; 3598c2ecf20Sopenharmony_ci goto error; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Loop while there are still messages to transfer. */ 3638c2ecf20Sopenharmony_ci while (i < num) { 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Check for special case: Small write followed 3668c2ecf20Sopenharmony_ci * by read to same I2C device. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (i < (num-1) 3698c2ecf20Sopenharmony_ci && msgs[i].addr == msgs[i+1].addr 3708c2ecf20Sopenharmony_ci && !(msgs[i].flags & I2C_M_RD) 3718c2ecf20Sopenharmony_ci && (msgs[i+1].flags & I2C_M_RD) 3728c2ecf20Sopenharmony_ci && (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) { 3738c2ecf20Sopenharmony_ci /* 3748c2ecf20Sopenharmony_ci * The DS28E17 has a combined transfer 3758c2ecf20Sopenharmony_ci * for small write+read. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci result = w1_f19_i2c_write_read(sl, msgs[i].addr, 3788c2ecf20Sopenharmony_ci msgs[i].buf, msgs[i].len, 3798c2ecf20Sopenharmony_ci msgs[i+1].buf, msgs[i+1].len); 3808c2ecf20Sopenharmony_ci if (result < 0) { 3818c2ecf20Sopenharmony_ci i = result; 3828c2ecf20Sopenharmony_ci goto error; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Check if we should interpret the read data 3878c2ecf20Sopenharmony_ci * as a length byte. The DS28E17 unfortunately 3888c2ecf20Sopenharmony_ci * has no read without stop, so we can just do 3898c2ecf20Sopenharmony_ci * another simple read in that case. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci if (msgs[i+1].flags & I2C_M_RECV_LEN) { 3928c2ecf20Sopenharmony_ci result = w1_f19_i2c_read(sl, msgs[i+1].addr, 3938c2ecf20Sopenharmony_ci &(msgs[i+1].buf[1]), msgs[i+1].buf[0]); 3948c2ecf20Sopenharmony_ci if (result < 0) { 3958c2ecf20Sopenharmony_ci i = result; 3968c2ecf20Sopenharmony_ci goto error; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Eat up read message, too. */ 4018c2ecf20Sopenharmony_ci i++; 4028c2ecf20Sopenharmony_ci } else if (msgs[i].flags & I2C_M_RD) { 4038c2ecf20Sopenharmony_ci /* Read transfer. */ 4048c2ecf20Sopenharmony_ci result = w1_f19_i2c_read(sl, msgs[i].addr, 4058c2ecf20Sopenharmony_ci msgs[i].buf, msgs[i].len); 4068c2ecf20Sopenharmony_ci if (result < 0) { 4078c2ecf20Sopenharmony_ci i = result; 4088c2ecf20Sopenharmony_ci goto error; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* 4128c2ecf20Sopenharmony_ci * Check if we should interpret the read data 4138c2ecf20Sopenharmony_ci * as a length byte. The DS28E17 unfortunately 4148c2ecf20Sopenharmony_ci * has no read without stop, so we can just do 4158c2ecf20Sopenharmony_ci * another simple read in that case. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RECV_LEN) { 4188c2ecf20Sopenharmony_ci result = w1_f19_i2c_read(sl, 4198c2ecf20Sopenharmony_ci msgs[i].addr, 4208c2ecf20Sopenharmony_ci &(msgs[i].buf[1]), 4218c2ecf20Sopenharmony_ci msgs[i].buf[0]); 4228c2ecf20Sopenharmony_ci if (result < 0) { 4238c2ecf20Sopenharmony_ci i = result; 4248c2ecf20Sopenharmony_ci goto error; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } else { 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * Write transfer. 4308c2ecf20Sopenharmony_ci * Stop condition only for last 4318c2ecf20Sopenharmony_ci * transfer. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci result = w1_f19_i2c_write(sl, 4348c2ecf20Sopenharmony_ci msgs[i].addr, 4358c2ecf20Sopenharmony_ci msgs[i].buf, 4368c2ecf20Sopenharmony_ci msgs[i].len, 4378c2ecf20Sopenharmony_ci i == (num-1)); 4388c2ecf20Sopenharmony_ci if (result < 0) { 4398c2ecf20Sopenharmony_ci i = result; 4408c2ecf20Sopenharmony_ci goto error; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Next message. */ 4458c2ecf20Sopenharmony_ci i++; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Are there still messages to send/receive? */ 4488c2ecf20Sopenharmony_ci if (i < num) { 4498c2ecf20Sopenharmony_ci /* Yes. Resume to same DS28E17. */ 4508c2ecf20Sopenharmony_ci if (w1_reset_resume_command(sl->master)) { 4518c2ecf20Sopenharmony_ci i = -EIO; 4528c2ecf20Sopenharmony_ci goto error; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cierror: 4588c2ecf20Sopenharmony_ci /* End onewire transaction. */ 4598c2ecf20Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Return number of messages processed or error. */ 4628c2ecf20Sopenharmony_ci return i; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* Get I2C adapter functionality. */ 4678c2ecf20Sopenharmony_cistatic u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci /* 4708c2ecf20Sopenharmony_ci * Plain I2C functions only. 4718c2ecf20Sopenharmony_ci * SMBus is emulated by the kernel's I2C layer. 4728c2ecf20Sopenharmony_ci * No "I2C_FUNC_SMBUS_QUICK" 4738c2ecf20Sopenharmony_ci * No "I2C_FUNC_SMBUS_READ_BLOCK_DATA" 4748c2ecf20Sopenharmony_ci * No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL" 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | 4778c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE | 4788c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA | 4798c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA | 4808c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_PROC_CALL | 4818c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | 4828c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK | 4838c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_PEC; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/* I2C adapter quirks. */ 4888c2ecf20Sopenharmony_cistatic const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = { 4898c2ecf20Sopenharmony_ci .max_read_len = W1_F19_READ_DATA_LIMIT, 4908c2ecf20Sopenharmony_ci}; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/* I2C algorithm. */ 4938c2ecf20Sopenharmony_cistatic const struct i2c_algorithm w1_f19_i2c_algorithm = { 4948c2ecf20Sopenharmony_ci .master_xfer = w1_f19_i2c_master_transfer, 4958c2ecf20Sopenharmony_ci .functionality = w1_f19_i2c_functionality, 4968c2ecf20Sopenharmony_ci}; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/* Read I2C speed from DS28E17. */ 5008c2ecf20Sopenharmony_cistatic int w1_f19_get_i2c_speed(struct w1_slave *sl) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct w1_f19_data *data = sl->family_data; 5038c2ecf20Sopenharmony_ci int result = -EIO; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Start onewire transaction. */ 5068c2ecf20Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Select slave. */ 5098c2ecf20Sopenharmony_ci if (w1_reset_select_slave(sl)) 5108c2ecf20Sopenharmony_ci goto error; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Read slave configuration byte. */ 5138c2ecf20Sopenharmony_ci w1_write_8(sl->master, W1_F19_READ_CONFIGURATION); 5148c2ecf20Sopenharmony_ci result = w1_read_8(sl->master); 5158c2ecf20Sopenharmony_ci if (result < 0 || result > 2) { 5168c2ecf20Sopenharmony_ci result = -EIO; 5178c2ecf20Sopenharmony_ci goto error; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Update speed in slave specific data. */ 5218c2ecf20Sopenharmony_ci data->speed = result; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cierror: 5248c2ecf20Sopenharmony_ci /* End onewire transaction. */ 5258c2ecf20Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return result; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/* Set I2C speed on DS28E17. */ 5328c2ecf20Sopenharmony_cistatic int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct w1_f19_data *data = sl->family_data; 5358c2ecf20Sopenharmony_ci const int i2c_speeds[3] = { 100, 400, 900 }; 5368c2ecf20Sopenharmony_ci u8 w1_buf[2]; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Select slave. */ 5398c2ecf20Sopenharmony_ci if (w1_reset_select_slave(sl)) 5408c2ecf20Sopenharmony_ci return -EIO; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci w1_buf[0] = W1_F19_WRITE_CONFIGURATION; 5438c2ecf20Sopenharmony_ci w1_buf[1] = speed; 5448c2ecf20Sopenharmony_ci w1_write_block(sl->master, w1_buf, 2); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Update speed in slave specific data. */ 5478c2ecf20Sopenharmony_ci data->speed = speed; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci int result; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* Start onewire transaction. */ 5598c2ecf20Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Set I2C speed on DS28E17. */ 5628c2ecf20Sopenharmony_ci result = __w1_f19_set_i2c_speed(sl, speed); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* End onewire transaction. */ 5658c2ecf20Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return result; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* Sysfs attributes. */ 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/* I2C speed attribute for a single chip. */ 5748c2ecf20Sopenharmony_cistatic ssize_t speed_show(struct device *dev, struct device_attribute *attr, 5758c2ecf20Sopenharmony_ci char *buf) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct w1_slave *sl = dev_to_w1_slave(dev); 5788c2ecf20Sopenharmony_ci int result; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Read current speed from slave. Updates data->speed. */ 5818c2ecf20Sopenharmony_ci result = w1_f19_get_i2c_speed(sl); 5828c2ecf20Sopenharmony_ci if (result < 0) 5838c2ecf20Sopenharmony_ci return result; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Return current speed value. */ 5868c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", result); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic ssize_t speed_store(struct device *dev, struct device_attribute *attr, 5908c2ecf20Sopenharmony_ci const char *buf, size_t count) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct w1_slave *sl = dev_to_w1_slave(dev); 5938c2ecf20Sopenharmony_ci int error; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Valid values are: "100", "400", "900" */ 5968c2ecf20Sopenharmony_ci if (count < 3 || count > 4 || !buf) 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci if (count == 4 && buf[3] != '\n') 5998c2ecf20Sopenharmony_ci return -EINVAL; 6008c2ecf20Sopenharmony_ci if (buf[1] != '0' || buf[2] != '0') 6018c2ecf20Sopenharmony_ci return -EINVAL; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Set speed on slave. */ 6048c2ecf20Sopenharmony_ci switch (buf[0]) { 6058c2ecf20Sopenharmony_ci case '1': 6068c2ecf20Sopenharmony_ci error = w1_f19_set_i2c_speed(sl, 0); 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case '4': 6098c2ecf20Sopenharmony_ci error = w1_f19_set_i2c_speed(sl, 1); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case '9': 6128c2ecf20Sopenharmony_ci error = w1_f19_set_i2c_speed(sl, 2); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci default: 6158c2ecf20Sopenharmony_ci return -EINVAL; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (error < 0) 6198c2ecf20Sopenharmony_ci return error; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Return bytes written. */ 6228c2ecf20Sopenharmony_ci return count; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(speed); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/* Busy stretch attribute for a single chip. */ 6298c2ecf20Sopenharmony_cistatic ssize_t stretch_show(struct device *dev, struct device_attribute *attr, 6308c2ecf20Sopenharmony_ci char *buf) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct w1_slave *sl = dev_to_w1_slave(dev); 6338c2ecf20Sopenharmony_ci struct w1_f19_data *data = sl->family_data; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Return current stretch value. */ 6368c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->stretch); 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic ssize_t stretch_store(struct device *dev, struct device_attribute *attr, 6408c2ecf20Sopenharmony_ci const char *buf, size_t count) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct w1_slave *sl = dev_to_w1_slave(dev); 6438c2ecf20Sopenharmony_ci struct w1_f19_data *data = sl->family_data; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Valid values are '1' to '9' */ 6468c2ecf20Sopenharmony_ci if (count < 1 || count > 2 || !buf) 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci if (count == 2 && buf[1] != '\n') 6498c2ecf20Sopenharmony_ci return -EINVAL; 6508c2ecf20Sopenharmony_ci if (buf[0] < '1' || buf[0] > '9') 6518c2ecf20Sopenharmony_ci return -EINVAL; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Set busy stretch value. */ 6548c2ecf20Sopenharmony_ci data->stretch = buf[0] & 0x0F; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Return bytes written. */ 6578c2ecf20Sopenharmony_ci return count; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(stretch); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* All attributes. */ 6648c2ecf20Sopenharmony_cistatic struct attribute *w1_f19_attrs[] = { 6658c2ecf20Sopenharmony_ci &dev_attr_speed.attr, 6668c2ecf20Sopenharmony_ci &dev_attr_stretch.attr, 6678c2ecf20Sopenharmony_ci NULL, 6688c2ecf20Sopenharmony_ci}; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic const struct attribute_group w1_f19_group = { 6718c2ecf20Sopenharmony_ci .attrs = w1_f19_attrs, 6728c2ecf20Sopenharmony_ci}; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic const struct attribute_group *w1_f19_groups[] = { 6758c2ecf20Sopenharmony_ci &w1_f19_group, 6768c2ecf20Sopenharmony_ci NULL, 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* Slave add and remove functions. */ 6818c2ecf20Sopenharmony_cistatic int w1_f19_add_slave(struct w1_slave *sl) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct w1_f19_data *data = NULL; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Allocate memory for slave specific data. */ 6868c2ecf20Sopenharmony_ci data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL); 6878c2ecf20Sopenharmony_ci if (!data) 6888c2ecf20Sopenharmony_ci return -ENOMEM; 6898c2ecf20Sopenharmony_ci sl->family_data = data; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Setup default I2C speed on slave. */ 6928c2ecf20Sopenharmony_ci switch (i2c_speed) { 6938c2ecf20Sopenharmony_ci case 100: 6948c2ecf20Sopenharmony_ci __w1_f19_set_i2c_speed(sl, 0); 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci case 400: 6978c2ecf20Sopenharmony_ci __w1_f19_set_i2c_speed(sl, 1); 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case 900: 7008c2ecf20Sopenharmony_ci __w1_f19_set_i2c_speed(sl, 2); 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci default: 7038c2ecf20Sopenharmony_ci /* 7048c2ecf20Sopenharmony_ci * A i2c_speed module parameter of anything else 7058c2ecf20Sopenharmony_ci * than 100, 400, 900 means not to touch the 7068c2ecf20Sopenharmony_ci * speed of the DS28E17. 7078c2ecf20Sopenharmony_ci * We assume 400kBaud, the power-on value. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci data->speed = 1; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* 7138c2ecf20Sopenharmony_ci * Setup default busy stretch 7148c2ecf20Sopenharmony_ci * configuration for the DS28E17. 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci data->stretch = i2c_stretch; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Setup I2C adapter. */ 7198c2ecf20Sopenharmony_ci data->adapter.owner = THIS_MODULE; 7208c2ecf20Sopenharmony_ci data->adapter.algo = &w1_f19_i2c_algorithm; 7218c2ecf20Sopenharmony_ci data->adapter.algo_data = sl; 7228c2ecf20Sopenharmony_ci strcpy(data->adapter.name, "w1-"); 7238c2ecf20Sopenharmony_ci strcat(data->adapter.name, sl->name); 7248c2ecf20Sopenharmony_ci data->adapter.dev.parent = &sl->dev; 7258c2ecf20Sopenharmony_ci data->adapter.quirks = &w1_f19_i2c_adapter_quirks; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return i2c_add_adapter(&data->adapter); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic void w1_f19_remove_slave(struct w1_slave *sl) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct w1_f19_data *family_data = sl->family_data; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Delete I2C adapter. */ 7358c2ecf20Sopenharmony_ci i2c_del_adapter(&family_data->adapter); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Free slave specific data. */ 7388c2ecf20Sopenharmony_ci devm_kfree(&sl->dev, family_data); 7398c2ecf20Sopenharmony_ci sl->family_data = NULL; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* Declarations within the w1 subsystem. */ 7448c2ecf20Sopenharmony_cistatic const struct w1_family_ops w1_f19_fops = { 7458c2ecf20Sopenharmony_ci .add_slave = w1_f19_add_slave, 7468c2ecf20Sopenharmony_ci .remove_slave = w1_f19_remove_slave, 7478c2ecf20Sopenharmony_ci .groups = w1_f19_groups, 7488c2ecf20Sopenharmony_ci}; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic struct w1_family w1_family_19 = { 7518c2ecf20Sopenharmony_ci .fid = W1_FAMILY_DS28E17, 7528c2ecf20Sopenharmony_ci .fops = &w1_f19_fops, 7538c2ecf20Sopenharmony_ci}; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci/* Module init and remove functions. */ 7578c2ecf20Sopenharmony_cistatic int __init w1_f19_init(void) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci return w1_register_family(&w1_family_19); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic void __exit w1_f19_fini(void) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci w1_unregister_family(&w1_family_19); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cimodule_init(w1_f19_init); 7688c2ecf20Sopenharmony_cimodule_exit(w1_f19_fini); 7698c2ecf20Sopenharmony_ci 770