summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattis fjallstrom <mattis@acm.org>2015-09-25 16:02:20 -0700
committermattis fjallstrom <mattis@acm.org>2015-09-25 16:02:20 -0700
commitd955f0cd9c528ed33d7da0c760f46572381c2039 (patch)
treef5fadaebd96d1fcc1747e90747db72a8f99e4a5d
parent9349b6c5b9f2bbe3cdaace0fc4774dc6baf5f7ba (diff)
downloadolio-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
-rw-r--r--arch/arm/configs/omap3_h1_defconfig1
-rw-r--r--arch/arm/mach-omap2/board-omap3h1.c317
-rw-r--r--drivers/power/bq27x00_battery.c119
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/triune/Kconfig4
-rw-r--r--drivers/staging/triune/Makefile5
-rw-r--r--drivers/staging/triune/ts81001.c194
-rw-r--r--drivers/staging/triune/ts81001.h57
-rw-r--r--include/linux/power/bq27x00_battery.h18
10 files changed, 564 insertions, 154 deletions
diff --git a/arch/arm/configs/omap3_h1_defconfig b/arch/arm/configs/omap3_h1_defconfig
index dfdbde194de..8a80eaf9278 100644
--- a/arch/arm/configs/omap3_h1_defconfig
+++ b/arch/arm/configs/omap3_h1_defconfig
@@ -2378,6 +2378,7 @@ CONFIG_ION=y
# CONFIG_WIMAX_GDM72XX is not set
# CONFIG_CED1401 is not set
# CONFIG_DGRP is not set
+CONFIG_OLIO_TS81001=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
diff --git a/arch/arm/mach-omap2/board-omap3h1.c b/arch/arm/mach-omap2/board-omap3h1.c
index 84dde6d63b0..14a0008d0b9 100644
--- a/arch/arm/mach-omap2/board-omap3h1.c
+++ b/arch/arm/mach-omap2/board-omap3h1.c
@@ -56,7 +56,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-
+#include <linux/power/bq27x00_battery.h>
#include "common.h"
#include "omap_device.h"
@@ -170,7 +170,7 @@ static struct omap_dss_device omap3h1_lcd_device = {
};
static struct omap_dss_device *omap3h1_dss_devices[] = {
- &omap3h1_lcd_device,
+ &omap3h1_lcd_device,
};
static struct omap_dss_board_info omap3h1_dss_data = {
@@ -191,9 +191,9 @@ static struct spi_board_info omap3h1_spi_board_info[] __initdata = {
};
static int __init omap3h1_spi_init(void) {
- spi_register_board_info(omap3h1_spi_board_info,
- ARRAY_SIZE(omap3h1_spi_board_info));
- return 0;
+ spi_register_board_info(omap3h1_spi_board_info,
+ ARRAY_SIZE(omap3h1_spi_board_info));
+ return 0;
}
@@ -210,11 +210,16 @@ static struct mpu_platform_data mpu_data = {
.int_config = 0x00,
.level_shifter = 1,
.orientation = { 0, -1, 0,
- -1, 0, 0,
- 0, 0, 1 },
+ -1, 0, 0,
+ 0, 0, 1 },
};
#endif
+
+static struct bq27x00_platform_data bq_platform_data = {
+ .charger_name = "3-0049",
+};
+
static struct lm3530_platform_data omap3h1_backlight_platform_data = {
.mode = LM3530_BL_MODE_SIMPLE_MANUAL,
//.als_input_mode = LM3530_INPUT_ALS1,
@@ -232,11 +237,9 @@ static struct lm3530_platform_data omap3h1_backlight_platform_data = {
.pwm_gpio = BACKLIGHT_PWM_GPIO,
};
-
-
static struct mxt_platform_data mxt_data = {
- .irqflags = IRQF_TRIGGER_FALLING,
- .suspend_mode = MXT_SUSPEND_DEEP_SLEEP
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .suspend_mode = MXT_SUSPEND_DEEP_SLEEP
};
@@ -246,10 +249,11 @@ static struct platform_device bcm20702_bluetooth_device = {
};
static struct platform_device omap3h1_dmic_codec = {
- .name = "dmic-codec",
- .id = -1,
+ .name = "dmic-codec",
+ .id = -1,
};
+
/* --------------------------------------------------------------------------- */
/* USB settings
*/
@@ -263,18 +267,18 @@ static struct omap_musb_board_data musb_board_data = {
};
static struct nop_usb_xceiv_platform_data nop_plat_data = {
- .type = USB_PHY_TYPE_USB2,
- .clk_rate = 60000000, /* 60 MHz */
- .needs_vcc = 1,
- .needs_reset = 0,
+ .type = USB_PHY_TYPE_USB2,
+ .clk_rate = 60000000, /* 60 MHz */
+ .needs_vcc = 1,
+ .needs_reset = 0,
};
static struct platform_device nop_phy_device = {
- .name = "nop_usb_xceiv",
- .id = -1,
- .dev = {
- .platform_data = &nop_plat_data,
- },
+ .name = "nop_usb_xceiv",
+ .id = -1,
+ .dev = {
+ .platform_data = &nop_plat_data,
+ },
};
@@ -289,124 +293,132 @@ static struct platform_device nop_phy_device = {
static struct i2c_board_info __initdata omap3h1_i2c1_board_info[] = {
- {
- },
+ {
+ },
#if defined (CONFIG_MACH_OMAP3_H1_DVT2) || defined (CONFIG_MACH_OMAP3_H1_PV)
};
static struct i2c_board_info __initdata omap3h1_i2c2_board_info[] = {
#endif
- {
+ {
#ifdef CONFIG_MACH_OMAP3_H1_PV2
- I2C_BOARD_INFO("lsm6ds3", 0x6a),
+ I2C_BOARD_INFO("lsm6ds3", 0x6a),
#else
- I2C_BOARD_INFO("mpu6515", 0x68),
- .platform_data = &mpu_data,
+ I2C_BOARD_INFO("mpu6515", 0x68),
+ .platform_data = &mpu_data,
#endif
- },
- {
- /* Backlight */
- I2C_BOARD_INFO("lm3530-led", 0x38),
- .platform_data = &omap3h1_backlight_platform_data,
- },
- {
- I2C_BOARD_INFO("mXT224", 0x4a),
- .platform_data = &mxt_data,
- },
- {
- I2C_BOARD_INFO("cm3391", 0x10),
- },
+ },
+ {
+ /* Backlight */
+ I2C_BOARD_INFO("lm3530-led", 0x38),
+ .platform_data = &omap3h1_backlight_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("mXT224", 0x4a),
+ .platform_data = &mxt_data,
+ },
+ {
+ I2C_BOARD_INFO("cm3391", 0x10),
+ },
#ifdef CONFIG_MACH_OMAP3_H1_EVT1
};
static struct i2c_board_info __initdata omap3h1_i2c3_board_info[] = {
#endif
- {
- I2C_BOARD_INFO("bq274xx", 0x55),
- },
+ {
+ I2C_BOARD_INFO("bq274xx", 0x55),
+ .platform_data = &bq_platform_data,
+ },
};
+#ifdef CONFIG_MACH_OMAP3_H1_PV2
+static struct i2c_board_info __initdata omap3h1_i2c3_board_info[] = {
+ {
+ I2C_BOARD_INFO("ts81001", 0x49),
+ },
+};
+#endif
/***************************************************************************
* omap_uart data
*/
/* Some notes:
- .dma_enabled = false,
- .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
- .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
- .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
- This one sets runtime pm autosuspend timeout - -1 disables runtime
- pm (that is, pm that's done while running, not sleeping).
- .autosuspend_timeout = DEFAULT_AUTOSUSPEND_DELAY, ( -1 or X ms. )
+ .dma_enabled = false,
+ .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+ .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
+ .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+ This one sets runtime pm autosuspend timeout - -1 disables runtime
+ pm (that is, pm that's done while running, not sleeping).
+ .autosuspend_timeout = DEFAULT_AUTOSUSPEND_DELAY, ( -1 or X ms. )
- Wakelock timeout: If there's an interrupt on the serial port, this is
- how long we expect to wait before the system is functional.
- .wakelock_timeout - for minnow, this is 150 (BT) or 50 (M4 debug).
- Can be left out.
+ Wakelock timeout: If there's an interrupt on the serial port, this is
+ how long we expect to wait before the system is functional.
+ .wakelock_timeout - for minnow, this is 150 (BT) or 50 (M4 debug).
+ Can be left out.
- .DTR_* -> can be left out. I can't find anyone using it.
+ .DTR_* -> can be left out. I can't find anyone using it.
- int DTR_gpio;
- int DTR_inverted;
- int DTR_present;
- bool wakeup_capable;
+ int DTR_gpio;
+ int DTR_inverted;
+ int DTR_present;
+ bool wakeup_capable;
- bool open_close_pm; - Minnow uses this for c55 only
- unsigned int rx_trig; Minnow, BT & debug only
+ bool open_close_pm; - Minnow uses this for c55 only
+ unsigned int rx_trig; Minnow, BT & debug only
- The flags field is not used (it's hardcoded in omap_serial_init_port).
+ The flags field is not used (it's hardcoded in omap_serial_init_port).
*/
static struct omap_uart_port_info omap_uart_ports[] = {
- {
- .dma_enabled = false, /* To specify DMA Mode */
- .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
- .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
- .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
- .autosuspend_timeout = 100,
- .wakelock_timeout = 150,
- .wake_peer = bcm_bt_lpm_exit_lpm_locked,
- .wakeup_capable = true,
- .rx_trig = 32,
+ {
+ .dma_enabled = false, /* To specify DMA Mode */
+ .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+ .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+ .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
+ .autosuspend_timeout = 100,
+ .wakelock_timeout = 150,
+ .wake_peer = bcm_bt_lpm_exit_lpm_locked,
+ .wakeup_capable = true,
+ .rx_trig = 32,
- /* OLIO: make sure RTS isn't enabled before we're ready */
+ /* OLIO: make sure RTS isn't enabled before we're ready */
- .rts_wait = true,
- .rts_enable_fn = rts_exit_sleep_mode,
- .rts_disable_fn = rts_enter_sleep_mode,
- },
- {
- .dma_enabled = false, /* To specify DMA Mode */
- .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
- .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
- .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
- .autosuspend_timeout = 0,
- .wakeup_capable = false,
- .rts_wait = false,
- .rts_enable_fn = NULL,
- .rts_disable_fn = NULL,
- },
- {
- .dma_enabled = false, /* To specify DMA Mode */
- .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
- .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
- .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
- .autosuspend_timeout = -1,
- .wakeup_capable = true,
- .rts_wait = false,
- .rts_enable_fn = NULL,
- .rts_disable_fn = NULL,
- },
- {
- .dma_enabled = false, /* To specify DMA Mode */
- .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
- .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
- .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
- .autosuspend_timeout = 0,
- .wakeup_capable = false,
- .rts_wait = false,
- .rts_enable_fn = NULL,
- .rts_disable_fn = NULL,
- },
+ .rts_wait = true,
+ .rts_enable_fn = rts_exit_sleep_mode,
+ .rts_disable_fn = rts_enter_sleep_mode,
+ },
+ {
+ .dma_enabled = false, /* To specify DMA Mode */
+ .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+ .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+ .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
+ .autosuspend_timeout = 0,
+ .wakeup_capable = false,
+ .rts_wait = false,
+ .rts_enable_fn = NULL,
+ .rts_disable_fn = NULL,
+ },
+ {
+ .dma_enabled = false, /* To specify DMA Mode */
+ .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+ .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+ .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
+ .autosuspend_timeout = -1,
+ .wakeup_capable = true,
+ .rts_wait = false,
+ .rts_enable_fn = NULL,
+ .rts_disable_fn = NULL,
+ },
+ {
+ .dma_enabled = false, /* To specify DMA Mode */
+ .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
+ .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
+ .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
+ .autosuspend_timeout = 0,
+ .wakeup_capable = false,
+ .rts_wait = false,
+ .rts_enable_fn = NULL,
+ .rts_disable_fn = NULL,
+ },
};
@@ -417,76 +429,75 @@ static struct omap_uart_port_info omap_uart_ports[] = {
static int __init omap3_h1_i2c_init(void)
{
- int acc_irq;
+ int acc_irq;
- /* In Linux 3.10 we need to request an IRQ through
- * gpio_to_irq. This means it can't be set at compile time, and
- * must be done at runtime. In other words, here.
- */
+ /* In Linux 3.10 we need to request an IRQ through
+ * gpio_to_irq. This means it can't be set at compile time, and
+ * must be done at runtime. In other words, here.
+ */
- gpio_request_one(ATMEL_MXT_GPIO, GPIOF_IN, "atmel_mxt_ts CHG");
+ gpio_request_one(ATMEL_MXT_GPIO, GPIOF_IN, "atmel_mxt_ts CHG");
gpio_request_one(MPUIRQ_GPIO, GPIOF_IN, "Accl IRQ pin");
- acc_irq = gpio_to_irq(MPUIRQ_GPIO);
+ acc_irq = gpio_to_irq(MPUIRQ_GPIO);
#if defined (CONFIG_MACH_OMAP3_H1_DVT2) || defined (CONFIG_MACH_OMAP3_H1_PV)
omap3h1_i2c2_board_info[2].irq = gpio_to_irq(ATMEL_MXT_GPIO);
- omap3h1_i2c2_board_info[0].irq = acc_irq;
+ omap3h1_i2c2_board_info[0].irq = acc_irq;
#else
omap3h1_i2c1_board_info[3].irq = gpio_to_irq(ATMEL_MXT_GPIO);
- omap3h1_i2c1_board_info[1].irq = acc_irq;
+ omap3h1_i2c1_board_info[1].irq = acc_irq;
#endif
#if defined (CONFIG_MACH_OMAP3_H1_PV)
- omap3h1_i2c2_board_info[4].irq = gpio_to_irq(CHG_GPOUT);
+ omap3h1_i2c2_board_info[4].irq = gpio_to_irq(CHG_GPOUT);
#endif
gpio_request_one(USB_CS, GPIOF_OUT_INIT_HIGH, "USB on");
- /* Register buses */
+ /* Register buses */
// omap_register_i2c_bus(1, 400, omap3h1_i2c1_board_info, ARRAY_SIZE(omap3h1_i2c1_board_info));
#if defined (CONFIG_MACH_OMAP3_H1_DVT2) || defined (CONFIG_MACH_OMAP3_H1_PV)
- omap_register_i2c_bus(2, 400, omap3h1_i2c2_board_info, ARRAY_SIZE(omap3h1_i2c2_board_info));
+ omap_register_i2c_bus(2, 400, omap3h1_i2c2_board_info,
+ ARRAY_SIZE(omap3h1_i2c2_board_info));
#else
omap_register_i2c_bus(2, 400, NULL, 0);
#endif
-#ifdef CONFIG_MACH_OMAP3_H1_EVT1
- omap_register_i2c_bus(3, 400, omap3h1_i2c3_board_info, ARRAY_SIZE(omap3h1_i2c3_board_info));
-#else
- omap_register_i2c_bus(3, 100, NULL, 0);
-#endif
+ omap_register_i2c_bus(3, 100, omap3h1_i2c3_board_info,
+ ARRAY_SIZE(omap3h1_i2c3_board_info));
+
return 0;
}
static struct platform_device *omap3h1_devices[] __initdata = {
- &bcm20702_bluetooth_device,
- &nop_phy_device,
- &omap3h1_dmic_codec,
+ &bcm20702_bluetooth_device,
+ &nop_phy_device,
+ &omap3h1_dmic_codec,
};
static void __init omap3_h1_init(void)
{
- /* Read what we can from the device tree */
+ /* Read what we can from the device tree */
- of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
+ of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
#ifdef CONFIG_MACH_OMAP3_H1_PV
- /* The PV units need reversed polarity for the sysclkreq pin. */
+ /* The PV units need reversed polarity for the sysclkreq pin. */
- omap2_prm_rmw_mod_reg_bits(OMAP3430_CLKREQ_POL_MASK,
- 0, OMAP3430_GR_MOD,
- OMAP3_PRM_POLCTRL_OFFSET);
+ omap2_prm_rmw_mod_reg_bits(OMAP3430_CLKREQ_POL_MASK,
+ 0, OMAP3430_GR_MOD,
+ OMAP3_PRM_POLCTRL_OFFSET);
#endif
board_nand_init(omap3h1_nand_partitions,
- ARRAY_SIZE(omap3h1_nand_partitions), NAND_CS,
- NAND_BUSWIDTH_16, NULL);
+ ARRAY_SIZE(omap3h1_nand_partitions), NAND_CS,
+ NAND_BUSWIDTH_16, NULL);
omap_sdrc_init(mt29c8g96_sdrc_params, mt29c8g96_sdrc_params);
-
- omap3_h1_i2c_init();
+
+ omap3_h1_i2c_init();
platform_add_devices(omap3h1_devices, ARRAY_SIZE(omap3h1_devices));
@@ -494,7 +505,7 @@ static void __init omap3_h1_init(void)
omap_serial_board_init(omap_uart_ports);
- omap_display_init(&omap3h1_dss_data);
+ omap_display_init(&omap3h1_dss_data);
usb_bind_phy("musb-hdrc.0.auto", 0, "nop_usb_xceiv"); /* "tusb-usb-h1" */
@@ -507,23 +518,23 @@ static const char *omap3_h1_boards_compat[] __initdata = {
};
DT_MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 (Flattened Device Tree)")
- .atag_offset = 0x100,
+.atag_offset = 0x100,
.reserve = omap_reserve,
.map_io = omap3_map_io,
.init_early = omap3630_init_early,
- /* .init_irq = omap3_init_irq, */
- .init_irq = omap_intc_of_init,
+/* .init_irq = omap3_init_irq, */
+ .init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_h1_init,
.init_late = omap3630_init_late,
- .init_time = omap3_sync32k_timer_init,
- /* .init_time = omap3_secure_sync32k_timer_init, */
+ .init_time = omap3_sync32k_timer_init,
+/* .init_time = omap3_secure_sync32k_timer_init, */
.dt_compat = omap3_h1_boards_compat,
.restart = omap3xxx_restart,
-MACHINE_END
+ MACHINE_END
#if 0 /* removing ... for now */
-MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 Board")
+ MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 Board")
.atag_offset = 0x100,
.reserve = omap_reserve,
.map_io = omap3_map_io,
@@ -532,9 +543,9 @@ MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 Board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_h1_init,
.init_late = omap3630_init_late,
- .init_time = omap3_sync32k_timer_init,
- /* .init_time = omap3_secure_sync32k_timer_init, */
- /* .dt_compat = omap3_h1_boards_compat, */
+ .init_time = omap3_sync32k_timer_init,
+/* .init_time = omap3_secure_sync32k_timer_init, */
+/* .dt_compat = omap3_h1_boards_compat, */
.restart = omap3xxx_restart,
-MACHINE_END
+ MACHINE_END
#endif
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 = &reg_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 */
diff --git a/include/linux/power/bq27x00_battery.h b/include/linux/power/bq27x00_battery.h
index a857f719bf4..a8999e26dcc 100644
--- a/include/linux/power/bq27x00_battery.h
+++ b/include/linux/power/bq27x00_battery.h
@@ -16,4 +16,22 @@ struct bq27000_platform_data {
int (*read)(struct device *dev, unsigned int);
};
+/**
+ * struct bq27x00_plaform_data - Platform data for bq27000 devices
+ * @charger_ops: Access functions for the charger
+ * Some information can't be deduced and needs to be retrieved
+ * directly from the charger. For example, if the device is
+ * running at full speed it may use more power than the charger
+ * can provide and a net outflow from the battery will be the
+ * result. With access to the charger the battery can still tell
+ * that it's on the charger (important information in certain
+ * circumstances).
+ */
+struct bq27x00_platform_data {
+ const char * charger_name;
+ struct device * charger_device;
+ struct i2c_client * charger_i2c;
+};
+
+
#endif