diff options
| author | mattis fjallstrom <mattis@acm.org> | 2015-09-25 16:02:20 -0700 | 
|---|---|---|
| committer | mattis fjallstrom <mattis@acm.org> | 2015-09-25 16:02:20 -0700 | 
| commit | d955f0cd9c528ed33d7da0c760f46572381c2039 (patch) | |
| tree | f5fadaebd96d1fcc1747e90747db72a8f99e4a5d /drivers | |
| parent | 9349b6c5b9f2bbe3cdaace0fc4774dc6baf5f7ba (diff) | |
| download | olio-linux-3.10-d955f0cd9c528ed33d7da0c760f46572381c2039.tar.xz olio-linux-3.10-d955f0cd9c528ed33d7da0c760f46572381c2039.zip | |
Adding support for ts81001, and modifying fuel gauge bq27 to check the status of the ts81001 when deciding if it's charging or not.
Change-Id: Iff0e890eecd86c82889f91075f83073ab2fd3036
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/power/bq27x00_battery.c | 119 | ||||
| -rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/staging/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/triune/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/staging/triune/Makefile | 5 | ||||
| -rw-r--r-- | drivers/staging/triune/ts81001.c | 194 | ||||
| -rw-r--r-- | drivers/staging/triune/ts81001.h | 57 | 
7 files changed, 381 insertions, 1 deletions
| diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index c10f48b20c8..8c1546b7d37 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -43,8 +43,22 @@  #include <asm/unaligned.h>  #include <linux/wakelock.h> +#include <linux/device.h>  #include <linux/power/bq27x00_battery.h> +#ifdef CONFIG_OLIO_TS81001 +#include "../staging/triune/ts81001.h" +#endif /* CONFIG_OLIO_TS81001 */ + + +#ifdef OLIODEBUG +#define do { olio_debug(format, ...) printk("OLIO %s: ", __FUNCTION__);	\ +		printk(format, ##__VA_ARGS__); } while(0) +#else +#define olio_debug(format, ...)  +#endif + +  #define DRIVER_VERSION			"1.2.0"  #define INVALID_REG_ADDR		0xFF @@ -1170,8 +1184,50 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,  	return 0;  } +#ifdef CONFIG_OLIO_TS81001 + +static int bq27x00_charger_status(struct bq27x00_device_info *di) { +	struct device * bq = di->dev; +	struct bq27x00_platform_data * pdata = bq->platform_data; +	struct ts81001 * ts81001; +	ts81001_state_t state; + +	olio_debug("entered\n"); + +	ts81001 = (struct ts81001 *) i2c_get_clientdata (pdata->charger_i2c);	 +	 +	if (ts81001 == NULL) { +		olio_debug("Couldn't find charger struct!"); +		return -EINVAL; +	} + +	olio_debug("Got client data for dev %s\n", dev_name(ts81001->dev)); + +	state = ts81001->ops->get_status(ts81001); + +	olio_debug("Got status\n");	 + +	switch (state)  +	{ +	case NOT_CHARGING: +		olio_debug("exiting, DISCHARGING\n"); +		return POWER_SUPPLY_STATUS_DISCHARGING; +	case PRECHARGE: +	case CHARGING_1C: +	case TOPOFF: +		olio_debug("exiting, CHARGING\n"); +		return POWER_SUPPLY_STATUS_CHARGING; +	default: +		olio_debug("Couldn't read status from ts81001 charger.\n"); +		olio_debug("exiting, EINVAL\n"); +		return -EINVAL; +	} +} + +#endif +  static int bq27x00_battery_status(struct bq27x00_device_info *di, -	union power_supply_propval *val) +				  union power_supply_propval *val)  {  	int status; @@ -1187,10 +1243,15 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,  	} else {  		if (di->cache.flags & BQ27XXX_FLAG_FC)  			status = POWER_SUPPLY_STATUS_FULL; +#ifdef CONFIG_OLIO_TS81001 +		else  +			status = bq27x00_charger_status (di); +#else  		else if (di->cache.flags & BQ27XXX_FLAG_DSC)  			status = POWER_SUPPLY_STATUS_DISCHARGING;  		else  			status = POWER_SUPPLY_STATUS_CHARGING; +#endif /* CONFIG_OLIO_TS81001 */  	}  	val->intval = status; @@ -1681,15 +1742,67 @@ static const struct attribute_group bq27x00_attr_group = {  	.attrs = bq27x00_attributes,  }; +#ifdef CONFIG_OLIO_TS81001 + +/*************************************************************************** + * bq27x00_set_platform_data - act on basic platform data + *  + * We get the name of the charger passed in through the platform data + * structure. Now we need to find the device that it corresponds to, and  + * it's i2c_client structure.  + *  + * Returns: + */ + +static int bq27x00_set_platform_data (struct bq27x00_platform_data * pdata) { +	int retval = 0; + +	olio_debug("entered\n"); + +	pdata->charger_device =  +		bus_find_device_by_name(&i2c_bus_type, +					NULL, +					pdata->charger_name); +	if (pdata->charger_device == NULL) { +		olio_debug("couldn't find charger device by name (name=%s)\n", +			    pdata->charger_name); +		retval = -ENXIO; +	} +	else {  /* device found */ +		pdata->charger_i2c = i2c_verify_client(pdata->charger_device); + +		if (pdata->charger_i2c == NULL) { +			olio_debug("couldn't find i2c_client for device name=%s\n", +				    pdata->charger_name); +			retval = -ENXIO; +		} +	} +	 +	olio_debug("exiting\n"); +		 +	return retval; +} + +#endif /* CONFIG_OLIO_TS81001 */ +  static int __init bq27x00_battery_probe(struct i2c_client *client,  				 const struct i2c_device_id *id)  {  	char *name;  	struct bq27x00_device_info *di; +	struct bq27x00_platform_data *pdata; +	  	int num;  	int retval = 0;  	u8 *regs; +#ifdef CONFIG_OLIO_TS81001 +	pdata = client->dev.platform_data; +	retval = bq27x00_set_platform_data (pdata); +	if (retval < 0)  +		return -EPROBE_DEFER; +#endif /* CONFIG_OLIO_TS81001 */ +  	/* Get new ID for the new battery device */  	retval = idr_pre_get(&battery_id, GFP_KERNEL);  	if (retval == 0) @@ -1988,3 +2101,7 @@ module_exit(bq27x00_battery_exit);  MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");  MODULE_DESCRIPTION("BQ27x00 battery monitor driver");  MODULE_LICENSE("GPL"); + +#ifdef OLIODEBUG +#undef OLIODEBUG +#endif diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index aefe820a800..1098075875d 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -140,4 +140,6 @@ source "drivers/staging/netlogic/Kconfig"  source "drivers/staging/dwc2/Kconfig" +source "drivers/staging/triune/Kconfig" +  endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 415772ea306..10cfb01009b 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -62,3 +62,4 @@ obj-$(CONFIG_FIREWIRE_SERIAL)	+= fwserial/  obj-$(CONFIG_ZCACHE)		+= zcache/  obj-$(CONFIG_GOLDFISH)		+= goldfish/  obj-$(CONFIG_USB_DWC2)		+= dwc2/ +obj-$(CONFIG_OLIO_TS81001)	+= triune/ diff --git a/drivers/staging/triune/Kconfig b/drivers/staging/triune/Kconfig new file mode 100644 index 00000000000..c16d93dfb6b --- /dev/null +++ b/drivers/staging/triune/Kconfig @@ -0,0 +1,4 @@ +config  OLIO_TS81001 +	tristate "OLIO Triune TS81001 driver" +	---help--- +	  Simplistic driver for the TS81001 wireless charger receiver from Triune as used by Olio. diff --git a/drivers/staging/triune/Makefile b/drivers/staging/triune/Makefile new file mode 100644 index 00000000000..a0fe548534b --- /dev/null +++ b/drivers/staging/triune/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Olio Triune charger driver +# + +obj-$(CONFIG_OLIO_TS81001) += ts81001.o diff --git a/drivers/staging/triune/ts81001.c b/drivers/staging/triune/ts81001.c new file mode 100644 index 00000000000..0562f4c9526 --- /dev/null +++ b/drivers/staging/triune/ts81001.c @@ -0,0 +1,194 @@ +/* ts81001.c - basic driver for Triune's 81001 */ + +/*  + * Triune ts81001 driver + *  + * Copyright 2015 Olio Devices + *  + * Mattis Fjallstrom (mattis@oliodevices.com) + */ + +/*  + * DESCRIPTION + * =========== + * This driver isn't strictly necessary. It provides access to some  + * of the basic functionality of the ts81001 from the linux kernel in  + * an easier way than otherwise. (The standard way would just be to  + * query the i2c bus). + * + * The plan is to also simplify updating the charger firmware ... but  + * that's not there yet. For now I'll also hardcode all the settings + * (like i2c bus address) but that may change later. + */ + +/*  + * Modification History + * ==================== + * 01a, 20150921, mfj  Created + */ + +/* Includes */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/iio/iio.h> + +#include "ts81001.h" + +/* Defines */ + +#ifdef OLIODEBUG +#define olio_debug(format, ...) printk ("OLIO %s: ", __FUNCTION__); printk (format, ##__VA_ARGS__) +#else +#define olio_debug(format, ...)  +#endif + +/* Globals */  + +const int TS81001_ADDR=0x49; +const u8  TS81001_STATUS_REG=0x10; + + +/*************************************************************************** + * Operations + */ + +static int ts81001_i2c_read (struct i2c_client * client, +			     u8 reg_addr,  +			     int len,  +			     u8 * data,  +			     bool b_lock) { +	int err = 0; +	struct i2c_msg msg[2]; + +	olio_debug (" entered\n");	 + +	msg[0].addr = client->addr; +	msg[0].flags = client->flags; +	msg[0].len = 1; +	msg[0].buf = ®_addr; + +	msg[1].addr = client->addr; +	msg[1].flags = client->flags | I2C_M_RD; +	msg[1].len = len; +	msg[1].buf = data; + +	if (b_lock) /* TODO: Add locking! */ +		err = i2c_transfer(client->adapter, msg, 2); +	else +		err = i2c_transfer(client->adapter, msg, 2); + +	olio_debug (" exiting\n"); + +	return err; +} + +/*************************************************************************** + * ts81001_get_status - get current charger state. + *  + * This function reads the status from the device on the i2c bus. The  + * ts81001 can be really slow to react, so we'll try again a few times + * before accepting failure.  + */ + +static int ts81001_get_status (struct ts81001 * ts) { +	u8 data; +	ts81001_state_t state; +	int len = 1; +	int err = 0; +	int retries = 2; +	int i; + +	olio_debug ("entered\n"); + +	for (i = 0; i < retries; i++) { +		err = ts81001_i2c_read (ts->client, TS81001_STATUS_REG, len, &data, false); +	 +		if (err <= 0) { +			olio_debug ("Error reading status from ts81001, err = %d\n", err); +			state = err; +		} else { +			state = (ts81001_state_t) data; +			break; +		} +	} + +	olio_debug ("exiting\n");	 + +	return state; +} + + +static struct ts81001_ops ts_ops = { +	.get_status = ts81001_get_status, +}; + +/*************************************************************************** + * probe + */ + + +static int ts81001_i2c_probe(struct i2c_client * client,  +			 const struct i2c_device_id * id) +{ +	struct ts81001 *ts81001; +	 +	int ret = 0; +	int chip_id = id->driver_data; + +	olio_debug("OLIO entered\n"); + +	ts81001 = kmalloc(sizeof(*ts81001), GFP_KERNEL); + +	if (!ts81001) +		return -ENOMEM; + +	ts81001->dev = &client->dev; +	ts81001->name = client->name; +	ts81001->client = client; +	ts81001->id = chip_id; + +	ts81001->ops = &ts_ops; + +	/* Fill out i2c_client struct */ + +	i2c_set_clientdata(client, ts81001); + +	olio_debug ("exiting\n"); + +	return ret; +} + +static int ts81001_i2c_remove(struct i2c_client * client) +{ +	struct ts81001 * ts = i2c_get_clientdata(client); + +	kfree (ts); + +	return 0; +} + +static const struct i2c_device_id ts81001_id_table[] = { +	{ TS81001_DEV_NAME }, +	{ }, +}; +MODULE_DEVICE_TABLE(i2c, ts81001_id_table); + +static struct i2c_driver ts81001_i2c_driver = { +	.probe = ts81001_i2c_probe, +	.remove = ts81001_i2c_remove, +	.id_table = ts81001_id_table, +	.driver = { +		.name = "ts81001", +		.owner = THIS_MODULE, +	}, +}; + +module_i2c_driver(ts81001_i2c_driver); + +MODULE_AUTHOR("Mattis Fjallstrom <mattis@oliodevice.com"); +MODULE_DESCRIPTION("Basic driver for TS81001"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/triune/ts81001.h b/drivers/staging/triune/ts81001.h new file mode 100644 index 00000000000..6d248254661 --- /dev/null +++ b/drivers/staging/triune/ts81001.h @@ -0,0 +1,57 @@ +/* + * ts81001.h - Triune ts81001 driver + * + * Copyright 2015 Olio Devices + *  + * Author: Mattis Fjallstrom + *  + *  This program is free software; you can redistribute it and/or modify it + *  under  the terms of the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the License, or (at your + *  option) any later version. + * + */ + +/* DESCRIPTION + * =========== + * This is the header for the Triune TS81001 driver. + */ + +/*  + * Modification History + * ==================== + * 01a, 20150921, mfj  Created + */ + +/* DEFINES */ + +#ifndef _CONFIG_TS81001_H +#define _CONFIG_TS81001_H + +#define TS81001_DEV_NAME "ts81001" + +/* INCLUDES */ + +#include <linux/regmap.h> + +typedef enum ts81001_state { +	NOT_CHARGING, +	PRECHARGE, +	CHARGING_1C, +	TOPOFF +} ts81001_state_t; + +struct ts81001 { +	struct device *dev; +	struct i2c_client *client; +	struct regmap *regmap; +	unsigned int id; +	char * name; +	struct ts81001_ops * ops; +}; + +struct ts81001_ops { +	int (*get_status) (struct ts81001 * ts); +}; + +#endif /* _CONFIG_TS81001_H */ |