From: Greg Meiste Date: Fri, 21 May 2010 15:45:27 +0000 (-0500) Subject: w1: slaves: ds2781: Add DS2781 driver X-Git-Tag: firefly_0821_release~9834^2~822 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3e2eea466ead894d6fc67325046f6da3ee295119;p=firefly-linux-kernel-4.4.55.git w1: slaves: ds2781: Add DS2781 driver Initial implementation of the DS2781 one wire slave driver Change-Id: Id7bb79fced794105d71e64ec9f5aa719f7da7797 Signed-off-by: Greg Meiste --- diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 1f51366417b9..bc13c3bea252 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -50,6 +50,19 @@ config W1_SLAVE_DS2760 If you are unsure, say N. +config W1_SLAVE_DS2781 + tristate "Dallas 2781 battery monitor chip" + depends on W1 + help + If you enable this you will have the DS2781 battery monitor + chip support. + + The battery monitor chip is used in many batteries/devices + as the one who is responsible for charging/discharging/monitoring + Li+ batteries. + + If you are unsure, say N. + config W1_SLAVE_BQ27000 tristate "BQ27000 slave support" depends on W1 diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index f1f51f19b129..70247ab8640e 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o +obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c new file mode 100644 index 000000000000..f1ae5cf85bad --- /dev/null +++ b/drivers/w1/slaves/w1_ds2781.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2010 Motorola, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Based on w1_ds2784.c which is: + * Copyright (C) 2009 HTC Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../w1.h" +#include "../w1_family.h" +#include "../w1_int.h" +#include "w1_ds2781.h" + +static 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); + + if (!dev) + return 0; + + mutex_lock(&sl->master->mutex); + + if (addr > DS2781_DATA_SIZE || addr < 0) { + count = 0; + goto out; + } + if (addr + count > DS2781_DATA_SIZE) + count = DS2781_DATA_SIZE - addr; + + if (!w1_reset_select_slave(sl)) { + if (!io) { + w1_write_8(sl->master, W1_DS2781_READ_DATA); + w1_write_8(sl->master, addr); + count = w1_read_block(sl->master, buf, count); + } else { + w1_write_8(sl->master, W1_DS2781_WRITE_DATA); + w1_write_8(sl->master, addr); + w1_write_block(sl->master, buf, count); + /* XXX w1_write_block returns void, not n_written */ + } + } + +out: + mutex_unlock(&sl->master->mutex); + + return count; +} + +int w1_ds2781_read(struct device *dev, char *buf, int addr, size_t count) +{ + return w1_ds2781_io(dev, buf, addr, count, 0); +} +EXPORT_SYMBOL(w1_ds2781_read); +int w1_ds2781_write(struct device *dev, char *buf, int addr, size_t count) +{ + return w1_ds2781_io(dev, buf, addr, count, 1); +} +EXPORT_SYMBOL(w1_ds2781_write); +static ssize_t w1_ds2781_read_bin(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + return w1_ds2781_read(dev, buf, off, count); +} + +static struct bin_attribute w1_ds2781_bin_attr = { + .attr = { + .name = "w1_slave", + .mode = S_IRUGO, + }, + .size = DS2781_DATA_SIZE, + .read = w1_ds2781_read_bin, +}; + +static DEFINE_IDR(bat_idr); +static DEFINE_MUTEX(bat_idr_lock); + +static int new_bat_id(void) +{ + int ret; + + while (1) { + int id; + + ret = idr_pre_get(&bat_idr, GFP_KERNEL); + if (ret == 0) + return -ENOMEM; + + mutex_lock(&bat_idr_lock); + ret = idr_get_new(&bat_idr, NULL, &id); + mutex_unlock(&bat_idr_lock); + + if (ret == 0) { + ret = id & MAX_ID_MASK; + break; + } else if (ret == -EAGAIN) { + continue; + } else { + break; + } + } + + return ret; +} + +static void release_bat_id(int id) +{ + mutex_lock(&bat_idr_lock); + idr_remove(&bat_idr, id); + mutex_unlock(&bat_idr_lock); +} + +static int w1_ds2781_add_slave(struct w1_slave *sl) +{ + int ret; + int id; + struct platform_device *pdev; + + id = new_bat_id(); + if (id < 0) { + ret = id; + goto noid; + } + + pdev = platform_device_alloc("ds2781-battery", id); + if (!pdev) { + ret = -ENOMEM; + goto pdev_alloc_failed; + } + pdev->dev.parent = &sl->dev; + + ret = platform_device_add(pdev); + if (ret) + goto pdev_add_failed; + + ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr); + if (ret) + goto bin_attr_failed; + + dev_set_drvdata(&sl->dev, pdev); + + return 0; + +bin_attr_failed: + platform_device_del(pdev); +pdev_add_failed: + platform_device_put(pdev); +pdev_alloc_failed: + release_bat_id(id); +noid: + return ret; +} + +static void w1_ds2781_remove_slave(struct w1_slave *sl) +{ + struct platform_device *pdev = dev_get_drvdata(&sl->dev); + int id = pdev->id; + + platform_device_unregister(pdev); + release_bat_id(id); + sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr); +} + +static struct w1_family_ops w1_ds2781_fops = { + .add_slave = w1_ds2781_add_slave, + .remove_slave = w1_ds2781_remove_slave, +}; + +static struct w1_family w1_ds2781_family = { + .fid = W1_FAMILY_DS2781, + .fops = &w1_ds2781_fops, +}; + +static int __init w1_ds2781_init(void) +{ + idr_init(&bat_idr); + return w1_register_family(&w1_ds2781_family); +} + +static void __exit w1_ds2781_exit(void) +{ + w1_unregister_family(&w1_ds2781_family); + idr_destroy(&bat_idr); +} + +module_init(w1_ds2781_init); +module_exit(w1_ds2781_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Motorola"); +MODULE_DESCRIPTION("1-wire Driver Dallas 2781 battery monitor chip"); diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h new file mode 100644 index 000000000000..0180fb9c59fa --- /dev/null +++ b/drivers/w1/slaves/w1_ds2781.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010 Motorola, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Based on w1_ds2784.h which is: + * Copyright (C) 2009 HTC Corporation + */ + +#ifndef __W1_DS2781_H__ +#define __W1_DS2781_H__ + +#ifdef __KERNEL__ + +/* Known commands to the DS2781 chip */ +#define W1_DS2781_READ_DATA 0x69 +#define W1_DS2781_WRITE_DATA 0x6C +#define W1_DS2781_COPY_DATA 0x48 +#define W1_DS2781_RECALL_DATA 0xB8 +#define W1_DS2781_LOCK 0x6A + +/* Number of valid register addresses */ +#define DS2781_DATA_SIZE 0x80 + +/* DS2781 1-wire slave memory map definitions */ +/* Reserved: 0x00 */ +#define DS2781_REG_STATUS 0x01 +#define DS2781_REG_RAAC_MSB 0x02 +#define DS2781_REG_RAAC_LSB 0x03 +#define DS2781_REG_RSAC_MSB 0x04 +#define DS2781_REG_RSAC_LSB 0x05 +#define DS2781_REG_RARC 0x06 +#define DS2781_REG_RSRC 0x07 +#define DS2781_REG_AVG_CURR_MSB 0x08 +#define DS2781_REG_AVG_CURR_LSB 0x09 +#define DS2781_REG_TEMP_MSB 0x0A +#define DS2781_REG_TEMP_LSB 0x0B +#define DS2781_REG_VOLT_MSB 0x0C +#define DS2781_REG_VOLT_LSB 0x0D +#define DS2781_REG_CURR_MSB 0x0E +#define DS2781_REG_CURR_LSB 0x0F +#define DS2781_REG_ACCUMULATE_CURR_MSB 0x10 +#define DS2781_REG_ACCUMULATE_CURR_LSB 0x11 +#define DS2781_REG_ACCUMULATE_CURR_LSB1 0x12 +#define DS2781_REG_ACCUMULATE_CURR_LSB2 0x13 +#define DS2781_REG_AGE_SCALAR 0x14 +#define DS2781_REG_SPECIAL_FEATURE 0x15 +#define DS2781_REG_FULL_MSB 0x16 +#define DS2781_REG_FULL_LSB 0x17 +#define DS2781_REG_ACTIVE_EMPTY_MSB 0x18 +#define DS2781_REG_ACTIVE_EMPTY_LSB 0x19 +#define DS2781_REG_STBY_EMPTY_MSB 0x1A +#define DS2781_REG_STBY_EMPTY_LSB 0x1B +/* Reserved: 0x1C - 0x1E */ +#define DS2781_REG_EEPROM 0x1F +#define DS2781_REG_USER_EEPROM 0x20 +/* Reserved: 0x30 - 0x5F */ +#define DS2781_REG_CTRL 0x60 +#define DS2781_REG_ACCUMULATION_BIAS 0x61 +#define DS2781_REG_AGE_CAPACITY_MSB 0x62 +#define DS2781_REG_AGE_CAPACITY_LSB 0x63 +#define DS2781_REG_CHARGE_VOLT 0x64 +#define DS2781_REG_MIN_CHARGE_CURR 0x65 +#define DS2781_REG_ACTIVE_EMPTY_VOLT 0x66 +#define DS2781_REG_ACTIVE_EMPTY_CURR 0x67 +#define DS2781_REG_ACTIVE_EMPTY_40 0x68 +#define DS2781_REG_RSNSP 0x69 +#define DS2781_REG_FULL_40_MSB 0x6A +#define DS2781_REG_FULL_40_LSB 0x6B +#define DS2781_REG_FULL_SEG_4_SLOPE 0x6C +#define DS2781_REG_FULL_SEG_3_SLOPE 0x6D +#define DS2781_REG_FULL_SEG_2_SLOPE 0x6E +#define DS2781_REG_FULL_SEG_1_SLOPE 0x6F +#define DS2781_REG_AE_SEG_4_SLOPE 0x70 +#define DS2781_REG_AE_SEG_3_SLOPE 0x71 +#define DS2781_REG_AE_SEG_2_SLOPE 0x72 +#define DS2781_REG_AE_SEG_1_SLOPE 0x73 +#define DS2781_REG_SE_SEG_4_SLOPE 0x74 +#define DS2781_REG_SE_SEG_3_SLOPE 0x75 +#define DS2781_REG_SE_SEG_2_SLOPE 0x76 +#define DS2781_REG_SE_SEG_1_SLOPE 0x77 +#define DS2781_REG_RSGAIN_MSB 0x78 +#define DS2781_REG_RSGAIN_LSB 0x79 +#define DS2781_REG_RSTC 0x7A +#define DS2781_REG_CURR_OFFSET_BIAS 0x7B +#define DS2781_REG_TBP34 0x7C +#define DS2781_REG_TBP23 0x7D +#define DS2781_REG_TBP12 0x7E +/* Reserved: 0x7F */ + +extern int w1_ds2781_read(struct device *dev, char *buf, int addr, + size_t count); +extern int w1_ds2781_write(struct device *dev, char *buf, int addr, + size_t count); + +#endif /* __KERNEL__ */ + +#endif /* __W1_DS2781_H__ */ diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 3ca1b9298f21..68310b46afd5 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -35,6 +35,7 @@ #define W1_THERM_DS18B20 0x28 #define W1_EEPROM_DS2431 0x2D #define W1_FAMILY_DS2760 0x30 +#define W1_FAMILY_DS2781 0x3D #define MAXNAMELEN 32