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 | |
| 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
| -rw-r--r-- | arch/arm/configs/omap3_h1_defconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/board-omap3h1.c | 317 | ||||
| -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 | ||||
| -rw-r--r-- | include/linux/power/bq27x00_battery.h | 18 |
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 = ®_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 |