2012-02-29 14:58:53 +01:00
/*
* 1 - Wire implementation for the ds2781 chip
*
* Author : Renata Sayakhova < renata @ oktetlabs . ru >
*
* Based on w1 - ds2780 driver
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/types.h>
# include <linux/platform_device.h>
# include <linux/mutex.h>
# include "../w1.h"
# include "../w1_int.h"
# include "../w1_family.h"
# include "w1_ds2781.h"
static int w1_ds2781_do_io ( struct device * dev , char * buf , int addr ,
size_t count , int io )
{
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
if ( addr > DS2781_DATA_SIZE | | addr < 0 )
return 0 ;
count = min_t ( int , count , DS2781_DATA_SIZE - addr ) ;
if ( w1_reset_select_slave ( sl ) = = 0 ) {
if ( io ) {
w1_write_8 ( sl - > master , W1_DS2781_WRITE_DATA ) ;
w1_write_8 ( sl - > master , addr ) ;
w1_write_block ( sl - > master , buf , count ) ;
} else {
w1_write_8 ( sl - > master , W1_DS2781_READ_DATA ) ;
w1_write_8 ( sl - > master , addr ) ;
count = w1_read_block ( sl - > master , buf , count ) ;
}
}
return count ;
}
int w1_ds2781_io ( struct device * dev , char * buf , int addr , size_t count ,
int io )
{
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret ;
if ( ! dev )
return - ENODEV ;
2012-05-18 15:59:52 +10:00
mutex_lock ( & sl - > master - > bus_mutex ) ;
2012-02-29 14:58:53 +01:00
ret = w1_ds2781_do_io ( dev , buf , addr , count , io ) ;
2012-05-18 15:59:52 +10:00
mutex_unlock ( & sl - > master - > bus_mutex ) ;
2012-02-29 14:58:53 +01:00
return ret ;
}
EXPORT_SYMBOL ( w1_ds2781_io ) ;
int w1_ds2781_eeprom_cmd ( struct device * dev , int addr , int cmd )
{
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
if ( ! dev )
return - EINVAL ;
2012-05-18 15:59:52 +10:00
mutex_lock ( & sl - > master - > bus_mutex ) ;
2012-02-29 14:58:53 +01:00
if ( w1_reset_select_slave ( sl ) = = 0 ) {
w1_write_8 ( sl - > master , cmd ) ;
w1_write_8 ( sl - > master , addr ) ;
}
2012-05-18 15:59:52 +10:00
mutex_unlock ( & sl - > master - > bus_mutex ) ;
2012-02-29 14:58:53 +01:00
return 0 ;
}
EXPORT_SYMBOL ( w1_ds2781_eeprom_cmd ) ;
2013-08-21 15:45:05 -07:00
static ssize_t w1_slave_read ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * bin_attr , char * buf ,
loff_t off , size_t count )
2012-02-29 14:58:53 +01:00
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
return w1_ds2781_io ( dev , buf , off , count , 0 ) ;
}
2013-08-21 15:45:05 -07:00
static BIN_ATTR_RO ( w1_slave , DS2781_DATA_SIZE ) ;
static struct bin_attribute * w1_ds2781_bin_attrs [ ] = {
& bin_attr_w1_slave ,
NULL ,
} ;
static const struct attribute_group w1_ds2781_group = {
. bin_attrs = w1_ds2781_bin_attrs ,
} ;
static const struct attribute_group * w1_ds2781_groups [ ] = {
& w1_ds2781_group ,
NULL ,
2012-02-29 14:58:53 +01:00
} ;
static int w1_ds2781_add_slave ( struct w1_slave * sl )
{
int ret ;
struct platform_device * pdev ;
2016-08-02 14:07:06 -07:00
pdev = platform_device_alloc ( " ds2781-battery " , PLATFORM_DEVID_AUTO ) ;
if ( ! pdev )
return - ENOMEM ;
2012-02-29 14:58:53 +01:00
pdev - > dev . parent = & sl - > dev ;
ret = platform_device_add ( pdev ) ;
if ( ret )
goto pdev_add_failed ;
dev_set_drvdata ( & sl - > dev , pdev ) ;
return 0 ;
pdev_add_failed :
2013-04-30 15:28:37 -07:00
platform_device_put ( pdev ) ;
2016-08-02 14:07:06 -07:00
2012-02-29 14:58:53 +01:00
return ret ;
}
static void w1_ds2781_remove_slave ( struct w1_slave * sl )
{
struct platform_device * pdev = dev_get_drvdata ( & sl - > dev ) ;
platform_device_unregister ( pdev ) ;
}
static struct w1_family_ops w1_ds2781_fops = {
. add_slave = w1_ds2781_add_slave ,
. remove_slave = w1_ds2781_remove_slave ,
2013-08-21 15:45:05 -07:00
. groups = w1_ds2781_groups ,
2012-02-29 14:58:53 +01:00
} ;
static struct w1_family w1_ds2781_family = {
. fid = W1_FAMILY_DS2781 ,
. fops = & w1_ds2781_fops ,
} ;
static int __init w1_ds2781_init ( void )
{
return w1_register_family ( & w1_ds2781_family ) ;
}
static void __exit w1_ds2781_exit ( void )
{
w1_unregister_family ( & w1_ds2781_family ) ;
}
module_init ( w1_ds2781_init ) ;
module_exit ( w1_ds2781_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Renata Sayakhova <renata@oktetlabs.ru> " ) ;
MODULE_DESCRIPTION ( " 1-wire Driver for Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC " ) ;
2013-05-26 20:06:50 +02:00
MODULE_ALIAS ( " w1-family- " __stringify ( W1_FAMILY_DS2781 ) ) ;