2019-06-03 07:44:46 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-09-20 23:52:46 +02:00
/*
* 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 400 kBaud , 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 ) ;