2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2011-05-26 16:26:04 -07:00
/*
* 1 - Wire implementation for the ds2780 chip
*
* Copyright ( C ) 2010 Indesign , LLC
*
* Author : Clifton Barnes < cabarnes @ indesign - llc . com >
*
* Based on w1 - ds2760 driver
*/
# 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 <linux/idr.h>
2017-06-05 08:52:08 -05:00
# include <linux/w1.h>
2011-05-26 16:26:04 -07:00
# include "w1_ds2780.h"
2017-06-05 08:52:08 -05:00
# define W1_FAMILY_DS2780 0x32
2011-11-02 13:39:52 -07:00
static int w1_ds2780_do_io ( struct device * dev , char * buf , int addr ,
size_t count , int io )
2011-05-26 16:26:04 -07:00
{
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
2011-11-02 13:39:52 -07:00
if ( addr > DS2780_DATA_SIZE | | addr < 0 )
return 0 ;
2011-05-26 16:26:04 -07:00
count = min_t ( int , count , DS2780_DATA_SIZE - addr ) ;
if ( w1_reset_select_slave ( sl ) = = 0 ) {
if ( io ) {
w1_write_8 ( sl - > master , W1_DS2780_WRITE_DATA ) ;
w1_write_8 ( sl - > master , addr ) ;
w1_write_block ( sl - > master , buf , count ) ;
} else {
w1_write_8 ( sl - > master , W1_DS2780_READ_DATA ) ;
w1_write_8 ( sl - > master , addr ) ;
count = w1_read_block ( sl - > master , buf , count ) ;
}
}
2011-11-02 13:39:52 -07:00
return count ;
}
int w1_ds2780_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 ) ;
2011-11-02 13:39:52 -07:00
ret = w1_ds2780_do_io ( dev , buf , addr , count , io ) ;
2012-05-18 15:59:52 +10:00
mutex_unlock ( & sl - > master - > bus_mutex ) ;
2011-05-26 16:26:04 -07:00
2011-11-02 13:39:52 -07:00
return ret ;
2011-05-26 16:26:04 -07:00
}
EXPORT_SYMBOL ( w1_ds2780_io ) ;
int w1_ds2780_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 ) ;
2011-05-26 16:26:04 -07: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 ) ;
2011-05-26 16:26:04 -07:00
return 0 ;
}
EXPORT_SYMBOL ( w1_ds2780_eeprom_cmd ) ;
2013-08-21 15:45:03 -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 )
2011-05-26 16:26:04 -07:00
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
return w1_ds2780_io ( dev , buf , off , count , 0 ) ;
}
2013-08-21 15:45:03 -07:00
static BIN_ATTR_RO ( w1_slave , DS2780_DATA_SIZE ) ;
static struct bin_attribute * w1_ds2780_bin_attrs [ ] = {
& bin_attr_w1_slave ,
NULL ,
} ;
static const struct attribute_group w1_ds2780_group = {
. bin_attrs = w1_ds2780_bin_attrs ,
} ;
static const struct attribute_group * w1_ds2780_groups [ ] = {
& w1_ds2780_group ,
NULL ,
2011-05-26 16:26:04 -07:00
} ;
static int w1_ds2780_add_slave ( struct w1_slave * sl )
{
int ret ;
struct platform_device * pdev ;
2016-08-02 14:07:06 -07:00
pdev = platform_device_alloc ( " ds2780-battery " , PLATFORM_DEVID_AUTO ) ;
if ( ! pdev )
return - ENOMEM ;
2011-05-26 16:26:04 -07: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:36 -07:00
platform_device_put ( pdev ) ;
2016-08-02 14:07:06 -07:00
2011-05-26 16:26:04 -07:00
return ret ;
}
static void w1_ds2780_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_ds2780_fops = {
. add_slave = w1_ds2780_add_slave ,
. remove_slave = w1_ds2780_remove_slave ,
2013-08-21 15:45:03 -07:00
. groups = w1_ds2780_groups ,
2011-05-26 16:26:04 -07:00
} ;
static struct w1_family w1_ds2780_family = {
. fid = W1_FAMILY_DS2780 ,
. fops = & w1_ds2780_fops ,
} ;
2016-08-02 14:07:09 -07:00
module_w1_family ( w1_ds2780_family ) ;
2011-05-26 16:26:04 -07:00
MODULE_AUTHOR ( " Clifton Barnes <cabarnes@indesign-llc.com> " ) ;
MODULE_DESCRIPTION ( " 1-wire Driver for Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC " ) ;
2017-05-16 15:02:12 -05:00
MODULE_LICENSE ( " GPL " ) ;
2013-05-26 20:06:50 +02:00
MODULE_ALIAS ( " w1-family- " __stringify ( W1_FAMILY_DS2780 ) ) ;