diff options
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 */ |