From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/power/supply/bq25700_charger.c | 536 ++++++++++++++++++++++++++++++++-------------------------- 1 files changed, 296 insertions(+), 240 deletions(-) diff --git a/kernel/drivers/power/supply/bq25700_charger.c b/kernel/drivers/power/supply/bq25700_charger.c index 5b2a516..7109613 100644 --- a/kernel/drivers/power/supply/bq25700_charger.c +++ b/kernel/drivers/power/supply/bq25700_charger.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TI BQ257000 charger driver + + * Copyright (c) 2021 Rockchip Electronics Co. Ltd. * - * Copyright (C) 2016 Rockchip Corporation - * - * 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. - * - * 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 FR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * + * Author: shengfeixu <xsf@rock-chips.com> */ #include <linux/power/bq25700-charge.h> @@ -22,6 +14,7 @@ #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/regmap.h> +#include <linux/regulator/driver.h> #include <linux/of_device.h> #include <linux/delay.h> #include <linux/usb/phy.h> @@ -54,6 +47,7 @@ #define MAX_CHARGEVOLTAGE 16800000 #define MAX_CHARGECURRETNT 8128000 #define MAX_OTGVOLTAGE 20800000 +#define MIN_OTGVOLTAGE 4280000 #define MAX_OTGCURRENT 6350000 enum bq25700_fields { @@ -168,27 +162,24 @@ bool charger_health_valid; bool battery_health_valid; bool battery_status_valid; - + int automode; + struct notifier_block nb; + struct bq2570x_platform_data plat_data; + struct device_node *notify_node; struct workqueue_struct *usb_charger_wq; struct workqueue_struct *dc_charger_wq; struct workqueue_struct *finish_sig_wq; struct delayed_work usb_work; - struct delayed_work pd_work; struct delayed_work host_work; struct delayed_work discnt_work; struct delayed_work usb_work1; - struct delayed_work pd_work1; struct delayed_work host_work1; struct delayed_work discnt_work1; struct delayed_work irq_work; struct notifier_block cable_cg_nb; - struct notifier_block cable_pd_nb; struct notifier_block cable_host_nb; - struct notifier_block cable_discnt_nb; struct notifier_block cable_cg_nb1; - struct notifier_block cable_pd_nb1; struct notifier_block cable_host_nb1; - struct notifier_block cable_discnt_nb1; struct extcon_dev *cable_edev; struct extcon_dev *cable_edev_1; int typec0_status; @@ -199,6 +190,7 @@ struct gpio_desc *typec1_discharge_io; struct gpio_desc *otg_mode_en_io; + struct regulator_dev *otg_vbus_reg; struct regmap *regmap; struct regmap_field *rmap_fields[F_MAX_FIELDS]; int chip_id; @@ -515,7 +507,13 @@ u32 size; }; -static const union { +static const struct bq25700_range sc8886_otg_range = { + .min = 1280000, + .max = 20800000, + .step = 128000, +}; + +static union { struct bq25700_range rt; struct bq25700_lookup lt; } bq25700_tables[] = { @@ -816,7 +814,7 @@ return 0; } -ssize_t bq25700_charge_info_show(struct device *dev, +static ssize_t bq25700_charge_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bq25700_device *charger = dev_get_drvdata(dev); @@ -944,12 +942,25 @@ dev_err(charger->dev, "ti,input-current is error\n"); return -ENODEV; } - if ((props[i].tbl_id == TBL_OTGVOL) && - (property > MAX_OTGVOLTAGE)) { - dev_err(charger->dev, "ti,ti,otg-voltage is error\n"); - return -ENODEV; + if (props[i].tbl_id == TBL_OTGVOL) { + if (of_device_is_compatible(charger->dev->of_node, + "southchip,sc8886")) { + bq25700_tables[TBL_OTGVOL].rt = sc8886_otg_range; + + if (property < MIN_OTGVOLTAGE) { + dev_err(charger->dev, + "ti,otg-voltage is error"); + return -ENODEV; + } + } + + if (property > MAX_OTGVOLTAGE) { + dev_err(charger->dev, "ti,otg-voltage is error\n"); + return -ENODEV; + }; } - if ((props[i].tbl_id == TBL_OTGVOL) && + + if ((props[i].tbl_id == TBL_OTGCUR) && (property > MAX_OTGCURRENT)) { dev_err(charger->dev, "ti,otg-current is error\n"); return -ENODEV; @@ -1231,6 +1242,7 @@ psy_cfg.supplied_to = bq25700_charger_supplied_to; psy_cfg.num_supplicants = ARRAY_SIZE(bq25700_charger_supplied_to); + psy_cfg.of_node = charger->dev->of_node; charger->supply_charger = power_supply_register(charger->dev, @@ -1238,6 +1250,71 @@ &psy_cfg); return PTR_ERR_OR_ZERO(charger->supply_charger); +} + +static void bq25700_discnt(struct bq25700_device *charger, enum tpyec_port_t port); + +static int bq2570x_pd_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct bq25700_device *bq = + container_of(nb, struct bq25700_device, nb); + struct power_supply *psy = v; + union power_supply_propval prop; + struct bq25700_state state; + int ret; + int vol_idx, cur_idx, chr_idx; + + if (val != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + /* Ignore event if it was not send by notify_node/notify_device */ + if (bq->notify_node) { + if (!psy->dev.parent || + psy->dev.parent->of_node != bq->notify_node) + return NOTIFY_OK; + } else if (bq->plat_data.notify_device) { + if (strcmp(psy->desc->name, bq->plat_data.notify_device) != 0) + return NOTIFY_OK; + } + + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &prop); + if (ret != 0) + return NOTIFY_OK; + /* online=0: USB out */ + if (prop.intval == 0) { + queue_delayed_work(bq->usb_charger_wq, &bq->discnt_work, + msecs_to_jiffies(10)); + return NOTIFY_OK; + } + + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + if (ret != 0) + return NOTIFY_OK; + if (prop.intval > 0) { + cur_idx = bq25700_find_idx(prop.intval, TBL_INPUTCUR); + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, + &prop); + if (ret != 0) + return NOTIFY_OK; + vol_idx = bq25700_find_idx((prop.intval - 1280000 - 3200000), TBL_INPUTVOL); + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, + &prop); + if (ret != 0) + return NOTIFY_OK; + chr_idx = bq25700_find_idx(prop.intval, TBL_ICHG); + + bq25700_field_write(bq, INPUT_CURRENT, cur_idx); + bq25700_field_write(bq, INPUT_VOLTAGE, vol_idx); + bq25700_field_write(bq, CHARGE_CURRENT, chr_idx); + dev_info(bq->dev, "INPUT_CURRENT:%d, INPUT_VOLTAGE:%d, CHARGE_CURRENT:%d\n", + cur_idx, vol_idx, chr_idx); + + bq25700_get_chip_state(bq, &state); + bq->state = state; + power_supply_changed(bq->supply_charger); + } + return NOTIFY_OK; } static irqreturn_t bq25700_irq_handler_thread(int irq, void *private) @@ -1304,101 +1381,6 @@ msleep(20); if (!IS_ERR_OR_NULL(charger->typec1_discharge_io)) gpiod_direction_output(charger->typec1_discharge_io, 0); -} - -static void bq25700_pd_connect(struct bq25700_device *charger, - struct extcon_dev *edev, - enum tpyec_port_t port) -{ - union extcon_property_value prop_val; - struct bq25700_state state; - int ret; - int vol, cur; - int vol_idx, cur_idx; - int i; - - if (charger->typec0_status == USB_STATUS_PD || - charger->typec1_status == USB_STATUS_PD) - return; - - if (extcon_get_state(edev, EXTCON_CHG_USB_FAST) > 0) { - ret = extcon_get_property(edev, EXTCON_CHG_USB_FAST, - EXTCON_PROP_USB_TYPEC_POLARITY, - &prop_val); - DBG("usb pd charge...\n"); - vol = prop_val.intval & 0xffff; - cur = prop_val.intval >> 15; - if (ret == 0) { - if (port == USB_TYPEC_0) { - charger->typec0_status = USB_STATUS_PD; - bq25700_enable_typec0(charger); - } else { - charger->typec1_status = USB_STATUS_PD; - bq25700_enable_typec1(charger); - } - - i = 0; - while (!bq25700_field_read(charger, AC_STAT) && i < 5) { - msleep(1000); - i++; - } - vol_idx = bq25700_find_idx((vol - 1280) * 1000, - TBL_INPUTVOL); - cur_idx = bq25700_find_idx(cur * 1000, TBL_INPUTCUR); - bq25700_field_write(charger, INPUT_VOLTAGE, vol_idx); - bq25700_field_write(charger, INPUT_CURRENT, cur_idx); - bq25700_field_write(charger, CHARGE_CURRENT, - charger->init_data.ichg); - } - - bq25700_get_chip_state(charger, &state); - charger->state = state; - power_supply_changed(charger->supply_charger); - } -} - -static void bq25700_pd_evt_worker(struct work_struct *work) -{ - struct bq25700_device *charger = container_of(work, - struct bq25700_device, pd_work.work); - struct extcon_dev *edev = charger->cable_edev; - - bq25700_pd_connect(charger, edev, USB_TYPEC_0); -} - -static void bq25700_pd_evt_worker1(struct work_struct *work) -{ - struct bq25700_device *charger = container_of(work, - struct bq25700_device, pd_work1.work); - struct extcon_dev *edev = charger->cable_edev_1; - - bq25700_pd_connect(charger, edev, USB_TYPEC_1); -} - -static int bq25700_pd_evt_notifier(struct notifier_block *nb, - unsigned long event, - void *ptr) -{ - struct bq25700_device *charger = - container_of(nb, struct bq25700_device, cable_pd_nb); - - queue_delayed_work(charger->usb_charger_wq, &charger->pd_work, - msecs_to_jiffies(10)); - - return NOTIFY_DONE; -} - -static int bq25700_pd_evt_notifier1(struct notifier_block *nb, - unsigned long event, - void *ptr) -{ - struct bq25700_device *charger = - container_of(nb, struct bq25700_device, cable_pd_nb1); - - queue_delayed_work(charger->usb_charger_wq, &charger->pd_work1, - msecs_to_jiffies(10)); - - return NOTIFY_DONE; } static void bq25700_charger_evt_handel(struct bq25700_device *charger, @@ -1481,6 +1463,7 @@ struct bq25700_device *charger = container_of(work, struct bq25700_device, usb_work.work); struct extcon_dev *edev = charger->cable_edev; + if (charger->usb_bc == 0) bq25700_charger_evt_handel(charger, edev, USB_TYPEC_0); else @@ -1522,24 +1505,25 @@ return NOTIFY_DONE; } +static void bq25700_set_otg_vbus(struct bq25700_device *charger, bool enable) +{ + DBG("OTG %s\n", enable ? "enable" : "disable"); + + if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) + gpiod_direction_output(charger->otg_mode_en_io, enable); + bq25700_field_write(charger, EN_OTG, enable); +} + static void bq25700_host_evt_worker(struct work_struct *work) { struct bq25700_device *charger = container_of(work, struct bq25700_device, host_work.work); struct extcon_dev *edev = charger->cable_edev; - /* Determine charger type */ - if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) { - if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) - gpiod_direction_output(charger->otg_mode_en_io, 1); - bq25700_field_write(charger, EN_OTG, 1); - DBG("OTG enable\n"); - } else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) { - if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) - gpiod_direction_output(charger->otg_mode_en_io, 0); - bq25700_field_write(charger, EN_OTG, 0); - DBG("OTG disable\n"); - } + if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) + bq25700_set_otg_vbus(charger, true); + else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) + bq25700_set_otg_vbus(charger, false); } static void bq25700_host_evt_worker1(struct work_struct *work) @@ -1548,18 +1532,10 @@ container_of(work, struct bq25700_device, host_work1.work); struct extcon_dev *edev = charger->cable_edev_1; - /* Determine charger type */ - if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) { - if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) - gpiod_direction_output(charger->otg_mode_en_io, 1); - bq25700_field_write(charger, EN_OTG, 1); - DBG("OTG enable\n"); - } else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) { - if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) - gpiod_direction_output(charger->otg_mode_en_io, 0); - bq25700_field_write(charger, EN_OTG, 0); - DBG("OTG disable\n"); - } + if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) > 0) + bq25700_set_otg_vbus(charger, true); + else if (extcon_get_state(edev, EXTCON_USB_VBUS_EN) == 0) + bq25700_set_otg_vbus(charger, false); } static int bq25700_host_evt_notifier(struct notifier_block *nb, @@ -1619,42 +1595,6 @@ discnt_work.work); bq25700_discnt(charger, USB_TYPEC_0); -} - -static void bq25700_discnt_evt_worker1(struct work_struct *work) -{ - struct bq25700_device *charger = container_of(work, - struct bq25700_device, - discnt_work1.work); - bq25700_discnt(charger, USB_TYPEC_1); -} - -static int bq25700_discnt_evt_notfier(struct notifier_block *nb, - unsigned long event, - void *ptr) -{ - struct bq25700_device *charger = - container_of(nb, struct bq25700_device, cable_discnt_nb); - - queue_delayed_work(charger->usb_charger_wq, - &charger->discnt_work, - msecs_to_jiffies(0)); - - return NOTIFY_DONE; -} - -static int bq25700_discnt_evt_notfier1(struct notifier_block *nb, - unsigned long event, - void *ptr) -{ - struct bq25700_device *charger = - container_of(nb, struct bq25700_device, cable_discnt_nb1); - - queue_delayed_work(charger->usb_charger_wq, - &charger->discnt_work1, - msecs_to_jiffies(0)); - - return NOTIFY_DONE; } static int bq25700_register_cg_extcon(struct bq25700_device *charger, @@ -1731,60 +1671,61 @@ return 0; } -static int bq25700_register_discnt_nb(struct bq25700_device *charger) -{ - int ret; - - /* Register discnt usb */ - if (charger->cable_edev) { - INIT_DELAYED_WORK(&charger->discnt_work, - bq25700_discnt_evt_worker); - charger->cable_discnt_nb.notifier_call = - bq25700_discnt_evt_notfier; - ret = extcon_register_notifier(charger->cable_edev, - EXTCON_USB, - &charger->cable_discnt_nb); - if (ret < 0) { - dev_err(charger->dev, - "failed to register notifier for HOST\n"); - return ret; - } - } - - if (charger->cable_edev_1) { - INIT_DELAYED_WORK(&charger->discnt_work1, - bq25700_discnt_evt_worker1); - charger->cable_discnt_nb1.notifier_call = - bq25700_discnt_evt_notfier1; - ret = extcon_register_notifier(charger->cable_edev_1, - EXTCON_USB, - &charger->cable_discnt_nb1); - if (ret < 0) { - dev_err(charger->dev, - "failed to register notifier for HOST\n"); - return ret; - } - } - - return 0; -} - static int bq25700_register_pd_nb(struct bq25700_device *charger) { - if (charger->cable_edev) { - INIT_DELAYED_WORK(&charger->pd_work, bq25700_pd_evt_worker); - charger->cable_pd_nb.notifier_call = bq25700_pd_evt_notifier; - extcon_register_notifier(charger->cable_edev, - EXTCON_CHG_USB_FAST, - &charger->cable_pd_nb); + struct power_supply *notify_psy = NULL; + int vol_idx, cur_idx; + int ret; + union power_supply_propval prop; + + if (charger->notify_node || charger->plat_data.notify_device) { + INIT_DELAYED_WORK(&charger->discnt_work, + bq25700_discnt_evt_worker); + charger->nb.notifier_call = bq2570x_pd_notifier_call; + ret = power_supply_reg_notifier(&charger->nb); + if (ret) { + dev_err(charger->dev, "failed to reg notifier: %d\n", ret); + return ret; + } + charger->automode = 1; + dev_info(charger->dev, "automode supported, waiting for events\n"); + } else { + charger->automode = -1; + dev_info(charger->dev, "automode not supported\n"); } - if (charger->cable_edev_1) { - INIT_DELAYED_WORK(&charger->pd_work1, bq25700_pd_evt_worker1); - charger->cable_pd_nb1.notifier_call = bq25700_pd_evt_notifier1; - extcon_register_notifier(charger->cable_edev_1, - EXTCON_CHG_USB_FAST, - &charger->cable_pd_nb1); + if (charger->nb.notifier_call) { + if (charger->dev->of_node) { + notify_psy = power_supply_get_by_phandle(charger->dev->of_node, + "ti,usb-charger-detection"); + if (IS_ERR_OR_NULL(notify_psy)) { + dev_info(charger->dev, "bq25700 notify_psy is error\n"); + notify_psy = NULL; + } + } else if (charger->plat_data.notify_device) { + notify_psy = power_supply_get_by_name( + charger->plat_data.notify_device); + } + } + + if (notify_psy) { + ret = power_supply_get_property(notify_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &prop); + if (ret != 0) + return ret; + ret = power_supply_get_property(notify_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop); + if (ret != 0) + return ret; + + cur_idx = bq25700_find_idx(prop.intval, TBL_INPUTCUR); + vol_idx = bq25700_find_idx((prop.intval - 1280000 - 3200000), TBL_INPUTVOL); + bq25700_field_write(charger, INPUT_CURRENT, cur_idx); + bq25700_field_write(charger, INPUT_VOLTAGE, vol_idx); + bq25700_field_write(charger, CHARGE_CURRENT, + charger->init_data.ichg); + dev_info(charger->dev, "INPUT_CURRENT:%d, INPUT_VOLTAGE:%d, CHARGE_CURRENT:%d\n", + cur_idx, vol_idx, charger->init_data.ichg); } return 0; @@ -1800,7 +1741,7 @@ charger->cable_host_nb.notifier_call = bq25700_host_evt_notifier; ret = extcon_register_notifier(charger->cable_edev, - EXTCON_USB_HOST, + EXTCON_USB_VBUS_EN, &charger->cable_host_nb); if (ret < 0) { dev_err(charger->dev, @@ -1815,7 +1756,7 @@ charger->cable_host_nb1.notifier_call = bq25700_host_evt_notifier1; ret = extcon_register_notifier(charger->cable_edev_1, - EXTCON_USB_HOST, + EXTCON_USB_VBUS_EN, &charger->cable_host_nb1); if (ret < 0) { dev_err(charger->dev, @@ -1823,6 +1764,77 @@ return -1; } } + + return 0; +} + +static int bq25700_otg_vbus_enable(struct regulator_dev *dev) +{ + struct bq25700_device *charger = rdev_get_drvdata(dev); + + bq25700_set_otg_vbus(charger, true); + + return 0; +} + +static int bq25700_otg_vbus_disable(struct regulator_dev *dev) +{ + struct bq25700_device *charger = rdev_get_drvdata(dev); + + bq25700_set_otg_vbus(charger, false); + + return 0; +} + +static int bq25700_otg_vbus_is_enabled(struct regulator_dev *dev) +{ + struct bq25700_device *charger = rdev_get_drvdata(dev); + u8 val; + int gpio_status = 1; + + val = bq25700_field_read(charger, EN_OTG); + if (!IS_ERR_OR_NULL(charger->otg_mode_en_io)) + gpio_status = gpiod_get_value(charger->otg_mode_en_io); + + return val && gpio_status ? 1 : 0; +} + +static const struct regulator_ops bq25700_otg_vbus_ops = { + .enable = bq25700_otg_vbus_enable, + .disable = bq25700_otg_vbus_disable, + .is_enabled = bq25700_otg_vbus_is_enabled, +}; + +static const struct regulator_desc bq25700_otg_vbus_desc = { + .name = "otg-vbus", + .of_match = "otg-vbus", + .regulators_node = of_match_ptr("regulators"), + .owner = THIS_MODULE, + .ops = &bq25700_otg_vbus_ops, + .type = REGULATOR_VOLTAGE, + .fixed_uV = 5000000, + .n_voltages = 1, +}; + +static int bq25700_register_otg_vbus_regulator(struct bq25700_device *charger) +{ + struct device_node *np; + struct regulator_config config = { }; + + np = of_get_child_by_name(charger->dev->of_node, "regulators"); + if (!np) { + dev_warn(charger->dev, "cannot find regulators node\n"); + return -ENXIO; + } + + config.dev = charger->dev; + config.driver_data = charger; + + charger->otg_vbus_reg = devm_regulator_register(charger->dev, + &bq25700_otg_vbus_desc, + &config); + if (IS_ERR(charger->otg_vbus_reg)) + return PTR_ERR(charger->otg_vbus_reg); return 0; } @@ -1854,21 +1866,31 @@ } else { charger->cable_edev_1 = edev1; } + /*set power_on input current*/ + bq25700_field_write(charger, INPUT_CURRENT, + charger->init_data.input_current_sdp); + if (!charger->pd_charge_only) bq25700_register_cg_nb(charger); - bq25700_register_host_nb(charger); - bq25700_register_discnt_nb(charger); + + if (bq25700_register_otg_vbus_regulator(charger) < 0) { + dev_warn(charger->dev, + "Cannot register otg vbus regulator\n"); + charger->otg_vbus_reg = NULL; + bq25700_register_host_nb(charger); + } + bq25700_register_pd_nb(charger); if (charger->cable_edev) { - schedule_delayed_work(&charger->host_work, 0); - schedule_delayed_work(&charger->pd_work, 0); + if (!charger->otg_vbus_reg) + schedule_delayed_work(&charger->host_work, 0); if (!charger->pd_charge_only) schedule_delayed_work(&charger->usb_work, 0); } if (charger->cable_edev_1) { - schedule_delayed_work(&charger->host_work1, 0); - schedule_delayed_work(&charger->pd_work1, 0); + if (!charger->otg_vbus_reg) + schedule_delayed_work(&charger->host_work1, 0); if (!charger->pd_charge_only) schedule_delayed_work(&charger->usb_work1, 0); } @@ -1918,7 +1940,11 @@ charger->usb_bc = 0; else charger->usb_bc = 1; + of_node_put(temp_np); + if (np) + charger->notify_node = of_parse_phandle(np, + "ti,usb-charger-detection", 0); return 0; } @@ -1944,6 +1970,8 @@ charger->dev = dev; charger_np = of_find_compatible_node(NULL, NULL, "ti,bq25700"); + if (!charger_np) + charger_np = of_find_compatible_node(NULL, NULL, "southchip,sc8885"); if (charger_np) { charger->regmap = devm_regmap_init_i2c(client, &bq25700_regmap_config); @@ -2006,6 +2034,20 @@ return -ENODEV; } + /* + * Make sure battery online, otherwise, writing INPUT_CURRENT and + * CHARGE_CURRENT would make system power off + */ + if (of_parse_phandle(charger->dev->of_node, "ti,battery", 0)) { + if (IS_ERR_OR_NULL(power_supply_get_by_phandle( + charger->dev->of_node, + "ti,battery"))) { + dev_info(charger->dev, "No battery found\n"); + return -EPROBE_DEFER; + } + dev_info(charger->dev, "Battery found\n"); + } + ret = bq25700_hw_init(charger); if (ret < 0) { dev_err(dev, "Cannot initialize the chip.\n"); @@ -2044,7 +2086,7 @@ return ret; } -void bq25700_shutdown(struct i2c_client *client) +static void bq25700_shutdown(struct i2c_client *client) { int vol_idx; struct bq25700_device *charger = i2c_get_clientdata(client); @@ -2053,16 +2095,28 @@ bq25700_field_write(charger, INPUT_VOLTAGE, vol_idx); bq25700_field_write(charger, INPUT_CURRENT, charger->init_data.input_current_sdp); + + if (!bq25700_field_read(charger, AC_STAT)) + bq25700_field_write(charger, EN_LWPWR, 1); } #ifdef CONFIG_PM_SLEEP static int bq25700_pm_suspend(struct device *dev) { + struct bq25700_device *charger = dev_get_drvdata(dev); + + if (!bq25700_field_read(charger, AC_STAT)) + bq25700_field_write(charger, EN_LWPWR, 1); + return 0; } static int bq25700_pm_resume(struct device *dev) { + struct bq25700_device *charger = dev_get_drvdata(dev); + + bq25700_field_write(charger, EN_LWPWR, 0); + return 0; } #endif @@ -2079,6 +2133,8 @@ static const struct of_device_id bq25700_of_match[] = { { .compatible = "ti,bq25700", }, { .compatible = "ti,bq25703", }, + { .compatible = "southchip,sc8885", }, + { .compatible = "southchip,sc8886", }, { }, }; MODULE_DEVICE_TABLE(of, bq25700_of_match); -- Gitblit v1.6.2