power supply and reset changes for the v4.21 series

* New core support
  - battery internal resistance
  - battery OCV capacity lookup table
  - support for custom sysfs attributes
 * Convert all drivers to use power-supply core support for custom sysfs attributes
 * bq24190-charger: bq24196 support
 * axp20x-charger: AXP813 support
 * sc27xx-battery: new fuel gauge driver
 * gpio-poweroff: support for specific active and inactive delays
 * Misc fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAlwlThQACgkQ2O7X88g7
 +pqmHg/+PPPeJVIfAAdxFe4KPvP/sAUnAGxqgJc7yeaKOq03eIWnm0JFbEsQLazM
 XDyk+8N7PQ254n2hU/DQln/OKrkVMo/QaOsn3HbbxaDbUiM5Mj8WjKOzgjWtgUy0
 OZOEk6n4SQNx6Ib7Wp/e+H6b/K+EglO5CVZDXmTBJfFKiKp5g4A3ZaUe8bCa1xuG
 4AB3QWQPomtI8o/nD37c4lpegojabUGN8hHI6r9TFT1PaYEzAmOQsb0NnGqEKAUw
 ECPBeH4jVoLN9Bie4u5Fgdr0lqukG+EAEHlHhPRea92oDLFfXEjPOI9JDM4XWBg/
 P47KNuvsVrIAUQ3rnCHUP4aC2ElL0G9bcEyADiLOuw9FIjMMjBm65pyRDORwkH+L
 TAu/28fL2Rzwenk+N8OLZ5lpvYlrqpDFISJkwO7gSGq4wyNW8I62GXJPFAYuSZsf
 dvlEOTgUCwNUnnF2ehx1AkvOBE+eh1CHvtcbKUMLwtBgWOhVi664Gm2znaLy6PwN
 XPkcRCNFIr/FZRuAo1x9GyxYv483Nk+27LcKfwz+HtmHHMRRDHDWtJ/K0KqK/y7a
 7HE7tBhCMpWikIXT1pAz7A0XYlMqfaMsyHlOqmeFgsNUBuDvJAArDz3Gff935PL3
 KGIr4lp+YeTHv6nJT/EMtGIG2dsJZUHh/NAtWZ07usI2fOgE3J4=
 =59iw
 -----END PGP SIGNATURE-----

Merge tag 'for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:

 - New core support:
    - battery internal resistance
    - battery OCV capacity lookup table
    - support for custom sysfs attributes

 - Convert all drivers to use power-supply core support for custom sysfs
   attributes

 - bq24190-charger: bq24196 support

 - axp20x-charger: AXP813 support

 - sc27xx-battery: new fuel gauge driver

 - gpio-poweroff: support for specific active and inactive delays

 - Misc fixes

* tag 'for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (53 commits)
  power: supply: bq25890: fix BAT_COMP field definition
  power: supply: gpio-charger: Do not use deprecated POWER_SUPPLY_TYPE_USB_*
  power: supply: ds2781: switch to devm_power_supply_register
  power: supply: ds2780: switch to devm_power_supply_register
  power: supply: ds2781: fix race-condition in bin attribute registration
  power: supply: ds2780: fix race-condition in bin attribute registration
  power: supply: pcf50633: fix race-condition in sysfs registration
  power: supply: charger-manager: fix race-condition in sysfs registration
  power: supply: charger-manager: simplify generation of sysfs attribute group name
  power: supply: bq24257: fix race-condition in sysfs registration
  power: supply: bq24190_charger: fix race-condition in sysfs registration
  power: supply: lp8788: fix race-condition in sysfs registration
  power: supply: ds2781: fix race-condition in sysfs registration
  power: supply: ds2780: fix race-condition in sysfs registration
  power: supply: bq2415x: fix race-condition in sysfs registration
  power: supply: core: add support for custom sysfs attributes
  power: supply: sc27xx: Save last battery capacity
  power: reset: at91-poweroff: move shdwc related data to one structure
  power: supply: sc27xx: Add suspend/resume interfaces
  power: supply: sc27xx: Add fuel gauge low voltage alarm
  ...
This commit is contained in:
Linus Torvalds 2018-12-28 20:22:45 -08:00
commit 579a700359
32 changed files with 1791 additions and 419 deletions

View file

@ -51,14 +51,16 @@ static const char *shdwc_wakeup_modes[] = {
[AT91_SHDW_WKMODE0_ANYLEVEL] = "any",
};
static void __iomem *at91_shdwc_base;
static struct clk *sclk;
static void __iomem *mpddrc_base;
static struct shdwc {
struct clk *sclk;
void __iomem *shdwc_base;
void __iomem *mpddrc_base;
} at91_shdwc;
static void __init at91_wakeup_status(struct platform_device *pdev)
{
const char *reason;
u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR);
u32 reg = readl(at91_shdwc.shdwc_base + AT91_SHDW_SR);
/* Simple power-on, just bail out */
if (!reg)
@ -75,11 +77,6 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
}
static void at91_poweroff(void)
{
writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
}
static void at91_lpddr_poweroff(void)
{
asm volatile(
/* Align to cache lines */
@ -89,15 +86,17 @@ static void at91_lpddr_poweroff(void)
" ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
/* Power down SDRAM0 */
" tst %0, #0\n\t"
" beq 1f\n\t"
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
/* Shutdown CPU */
" str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
"1: str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
" b .\n\t"
:
: "r" (mpddrc_base),
: "r" (at91_shdwc.mpddrc_base),
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
"r" (at91_shdwc_base),
"r" (at91_shdwc.shdwc_base),
"r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
: "r6");
}
@ -147,7 +146,7 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
mode |= AT91_SHDW_RTTWKEN;
writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR);
writel(wakeup_mode | mode, at91_shdwc.shdwc_base + AT91_SHDW_MR);
}
static int __init at91_poweroff_probe(struct platform_device *pdev)
@ -158,15 +157,15 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(at91_shdwc_base))
return PTR_ERR(at91_shdwc_base);
at91_shdwc.shdwc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(at91_shdwc.shdwc_base))
return PTR_ERR(at91_shdwc.shdwc_base);
sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(sclk))
return PTR_ERR(sclk);
at91_shdwc.sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(at91_shdwc.sclk))
return PTR_ERR(at91_shdwc.sclk);
ret = clk_prepare_enable(sclk);
ret = clk_prepare_enable(at91_shdwc.sclk);
if (ret) {
dev_err(&pdev->dev, "Could not enable slow clock\n");
return ret;
@ -177,44 +176,47 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
if (pdev->dev.of_node)
at91_poweroff_dt_set_wakeup_mode(pdev);
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
if (np) {
at91_shdwc.mpddrc_base = of_iomap(np, 0);
of_node_put(np);
if (!at91_shdwc.mpddrc_base) {
ret = -ENOMEM;
goto clk_disable;
}
ddr_type = readl(at91_shdwc.mpddrc_base + AT91_DDRSDRC_MDR) &
AT91_DDRSDRC_MD;
if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 &&
ddr_type != AT91_DDRSDRC_MD_LPDDR3) {
iounmap(at91_shdwc.mpddrc_base);
at91_shdwc.mpddrc_base = NULL;
}
}
pm_power_off = at91_poweroff;
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
if (!np)
return 0;
mpddrc_base = of_iomap(np, 0);
of_node_put(np);
if (!mpddrc_base)
return 0;
ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
(ddr_type == AT91_DDRSDRC_MD_LPDDR3))
pm_power_off = at91_lpddr_poweroff;
else
iounmap(mpddrc_base);
return 0;
clk_disable:
clk_disable_unprepare(at91_shdwc.sclk);
return ret;
}
static int __exit at91_poweroff_remove(struct platform_device *pdev)
{
if (pm_power_off == at91_poweroff ||
pm_power_off == at91_lpddr_poweroff)
if (pm_power_off == at91_poweroff)
pm_power_off = NULL;
clk_disable_unprepare(sclk);
if (at91_shdwc.mpddrc_base)
iounmap(at91_shdwc.mpddrc_base);
clk_disable_unprepare(at91_shdwc.sclk);
return 0;
}
static const struct of_device_id at91_ramc_of_match[] = {
{ .compatible = "atmel,sama5d3-ddramc", },
{ /* sentinel */ }
};
static const struct of_device_id at91_poweroff_of_match[] = {
{ .compatible = "atmel,at91sam9260-shdwc", },
{ .compatible = "atmel,at91sam9rl-shdwc", },

View file

@ -26,6 +26,8 @@
*/
static struct gpio_desc *reset_gpio;
static u32 timeout = DEFAULT_TIMEOUT_MS;
static u32 active_delay = 100;
static u32 inactive_delay = 100;
static void gpio_poweroff_do_poweroff(void)
{
@ -33,10 +35,11 @@ static void gpio_poweroff_do_poweroff(void)
/* drive it active, also inactive->active edge */
gpiod_direction_output(reset_gpio, 1);
mdelay(100);
mdelay(active_delay);
/* drive inactive, also active->inactive edge */
gpiod_set_value_cansleep(reset_gpio, 0);
mdelay(100);
mdelay(inactive_delay);
/* drive it active, also inactive->active edge */
gpiod_set_value_cansleep(reset_gpio, 1);
@ -66,6 +69,9 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
else
flags = GPIOD_OUT_LOW;
device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay);
device_property_read_u32(&pdev->dev, "inactive-delay-ms",
&inactive_delay);
device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);

View file

@ -26,6 +26,13 @@ struct ocelot_reset_context {
#define SOFT_CHIP_RST BIT(0)
#define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
#define IF_SI_OWNER_MASK GENMASK(1, 0)
#define IF_SI_OWNER_SISL 0
#define IF_SI_OWNER_SIBM 1
#define IF_SI_OWNER_SIMC 2
#define IF_SI_OWNER_OFFSET 4
static int ocelot_restart_handle(struct notifier_block *this,
unsigned long mode, void *cmd)
{
@ -37,6 +44,11 @@ static int ocelot_restart_handle(struct notifier_block *this,
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
CORE_RST_PROTECT, 0);
/* Make the SI back to boot mode */
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
IF_SI_OWNER_MASK << IF_SI_OWNER_OFFSET,
IF_SI_OWNER_SIBM << IF_SI_OWNER_OFFSET);
writel(SOFT_CHIP_RST, ctx->base);
pr_emerg("Unable to restart system\n");

View file

@ -652,4 +652,12 @@ config CHARGER_SC2731
Say Y here to enable support for battery charging with SC2731
PMIC chips.
config FUEL_GAUGE_SC27XX
tristate "Spreadtrum SC27XX fuel gauge driver"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
depends on IIO
help
Say Y here to enable support for fuel gauge with SC27XX
PMIC chips.
endif # POWER_SUPPLY

View file

@ -86,3 +86,4 @@ obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o

View file

@ -27,6 +27,16 @@
#define AXP20X_PWR_STATUS_ACIN_PRESENT BIT(7)
#define AXP20X_PWR_STATUS_ACIN_AVAIL BIT(6)
#define AXP813_VHOLD_MASK GENMASK(5, 3)
#define AXP813_VHOLD_UV_TO_BIT(x) ((((x) / 100000) - 40) << 3)
#define AXP813_VHOLD_REG_TO_UV(x) \
(((((x) & AXP813_VHOLD_MASK) >> 3) + 40) * 100000)
#define AXP813_CURR_LIMIT_MASK GENMASK(2, 0)
#define AXP813_CURR_LIMIT_UA_TO_BIT(x) (((x) / 500000) - 3)
#define AXP813_CURR_LIMIT_REG_TO_UA(x) \
((((x) & AXP813_CURR_LIMIT_MASK) + 3) * 500000)
#define DRVNAME "axp20x-ac-power-supply"
struct axp20x_ac_power {
@ -102,6 +112,27 @@ static int axp20x_ac_power_get_property(struct power_supply *psy,
return 0;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
if (ret)
return ret;
val->intval = AXP813_VHOLD_REG_TO_UV(reg);
return 0;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
if (ret)
return ret;
val->intval = AXP813_CURR_LIMIT_REG_TO_UA(reg);
/* AXP813 datasheet defines values 11x as 4000mA */
if (val->intval > 4000000)
val->intval = 4000000;
return 0;
default:
return -EINVAL;
}
@ -109,6 +140,43 @@ static int axp20x_ac_power_get_property(struct power_supply *psy,
return -EINVAL;
}
static int axp813_ac_power_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
if (val->intval < 4000000 || val->intval > 4700000)
return -EINVAL;
return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
AXP813_VHOLD_MASK,
AXP813_VHOLD_UV_TO_BIT(val->intval));
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (val->intval < 1500000 || val->intval > 4000000)
return -EINVAL;
return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
AXP813_CURR_LIMIT_MASK,
AXP813_CURR_LIMIT_UA_TO_BIT(val->intval));
default:
return -EINVAL;
}
return -EINVAL;
}
static int axp813_ac_power_prop_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
}
static enum power_supply_property axp20x_ac_power_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
@ -123,6 +191,14 @@ static enum power_supply_property axp22x_ac_power_properties[] = {
POWER_SUPPLY_PROP_ONLINE,
};
static enum power_supply_property axp813_ac_power_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
};
static const struct power_supply_desc axp20x_ac_power_desc = {
.name = "axp20x-ac",
.type = POWER_SUPPLY_TYPE_MAINS,
@ -139,6 +215,16 @@ static const struct power_supply_desc axp22x_ac_power_desc = {
.get_property = axp20x_ac_power_get_property,
};
static const struct power_supply_desc axp813_ac_power_desc = {
.name = "axp813-ac",
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = axp813_ac_power_properties,
.num_properties = ARRAY_SIZE(axp813_ac_power_properties),
.property_is_writeable = axp813_ac_power_prop_writeable,
.get_property = axp20x_ac_power_get_property,
.set_property = axp813_ac_power_set_property,
};
struct axp_data {
const struct power_supply_desc *power_desc;
bool acin_adc;
@ -154,6 +240,11 @@ static const struct axp_data axp22x_data = {
.acin_adc = false,
};
static const struct axp_data axp813_data = {
.power_desc = &axp813_ac_power_desc,
.acin_adc = false,
};
static int axp20x_ac_power_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@ -234,6 +325,9 @@ static const struct of_device_id axp20x_ac_power_match[] = {
}, {
.compatible = "x-powers,axp221-ac-power-supply",
.data = &axp22x_data,
}, {
.compatible = "x-powers,axp813-ac-power-supply",
.data = &axp813_data,
}, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, axp20x_ac_power_match);

View file

@ -10,6 +10,7 @@
* option) any later version.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>

View file

@ -16,6 +16,7 @@
*/
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/regmap.h>
@ -29,17 +30,17 @@
#include <linux/mfd/axp20x.h>
#include <linux/extcon.h>
#define PS_STAT_VBUS_TRIGGER (1 << 0)
#define PS_STAT_BAT_CHRG_DIR (1 << 2)
#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3)
#define PS_STAT_VBUS_VALID (1 << 4)
#define PS_STAT_VBUS_PRESENT (1 << 5)
#define PS_STAT_VBUS_TRIGGER BIT(0)
#define PS_STAT_BAT_CHRG_DIR BIT(2)
#define PS_STAT_VBAT_ABOVE_VHOLD BIT(3)
#define PS_STAT_VBUS_VALID BIT(4)
#define PS_STAT_VBUS_PRESENT BIT(5)
#define CHRG_STAT_BAT_SAFE_MODE (1 << 3)
#define CHRG_STAT_BAT_VALID (1 << 4)
#define CHRG_STAT_BAT_PRESENT (1 << 5)
#define CHRG_STAT_CHARGING (1 << 6)
#define CHRG_STAT_PMIC_OTP (1 << 7)
#define CHRG_STAT_BAT_SAFE_MODE BIT(3)
#define CHRG_STAT_BAT_VALID BIT(4)
#define CHRG_STAT_BAT_PRESENT BIT(5)
#define CHRG_STAT_CHARGING BIT(6)
#define CHRG_STAT_PMIC_OTP BIT(7)
#define VBUS_ISPOUT_CUR_LIM_MASK 0x03
#define VBUS_ISPOUT_CUR_LIM_BIT_POS 0
@ -52,33 +53,33 @@
#define VBUS_ISPOUT_VHOLD_SET_OFFSET 4000 /* 4000mV */
#define VBUS_ISPOUT_VHOLD_SET_LSB_RES 100 /* 100mV */
#define VBUS_ISPOUT_VHOLD_SET_4300MV 0x3 /* 4300mV */
#define VBUS_ISPOUT_VBUS_PATH_DIS (1 << 7)
#define VBUS_ISPOUT_VBUS_PATH_DIS BIT(7)
#define CHRG_CCCV_CC_MASK 0xf /* 4 bits */
#define CHRG_CCCV_CC_BIT_POS 0
#define CHRG_CCCV_CC_OFFSET 200 /* 200mA */
#define CHRG_CCCV_CC_LSB_RES 200 /* 200mA */
#define CHRG_CCCV_ITERM_20P (1 << 4) /* 20% of CC */
#define CHRG_CCCV_ITERM_20P BIT(4) /* 20% of CC */
#define CHRG_CCCV_CV_MASK 0x60 /* 2 bits */
#define CHRG_CCCV_CV_BIT_POS 5
#define CHRG_CCCV_CV_4100MV 0x0 /* 4.10V */
#define CHRG_CCCV_CV_4150MV 0x1 /* 4.15V */
#define CHRG_CCCV_CV_4200MV 0x2 /* 4.20V */
#define CHRG_CCCV_CV_4350MV 0x3 /* 4.35V */
#define CHRG_CCCV_CHG_EN (1 << 7)
#define CHRG_CCCV_CHG_EN BIT(7)
#define CNTL2_CC_TIMEOUT_MASK 0x3 /* 2 bits */
#define CNTL2_CC_TIMEOUT_OFFSET 6 /* 6 Hrs */
#define CNTL2_CC_TIMEOUT_LSB_RES 2 /* 2 Hrs */
#define CNTL2_CC_TIMEOUT_12HRS 0x3 /* 12 Hrs */
#define CNTL2_CHGLED_TYPEB (1 << 4)
#define CNTL2_CHG_OUT_TURNON (1 << 5)
#define CNTL2_CHGLED_TYPEB BIT(4)
#define CNTL2_CHG_OUT_TURNON BIT(5)
#define CNTL2_PC_TIMEOUT_MASK 0xC0
#define CNTL2_PC_TIMEOUT_OFFSET 40 /* 40 mins */
#define CNTL2_PC_TIMEOUT_LSB_RES 10 /* 10 mins */
#define CNTL2_PC_TIMEOUT_70MINS 0x3
#define CHRG_ILIM_TEMP_LOOP_EN (1 << 3)
#define CHRG_ILIM_TEMP_LOOP_EN BIT(3)
#define CHRG_VBUS_ILIM_MASK 0xf0
#define CHRG_VBUS_ILIM_BIT_POS 4
#define CHRG_VBUS_ILIM_100MA 0x0 /* 100mA */
@ -94,7 +95,7 @@
#define CHRG_VLTFC_0C 0xA5 /* 0 DegC */
#define CHRG_VHTFC_45C 0x1F /* 45 DegC */
#define FG_CNTL_OCV_ADJ_EN (1 << 3)
#define FG_CNTL_OCV_ADJ_EN BIT(3)
#define CV_4100MV 4100 /* 4100mV */
#define CV_4150MV 4150 /* 4150mV */

View file

@ -1032,54 +1032,6 @@ static int bq2415x_power_supply_get_property(struct power_supply *psy,
return 0;
}
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
{
int ret;
int chip;
char revstr[8];
struct power_supply_config psy_cfg = {
.drv_data = bq,
.of_node = bq->dev->of_node,
};
bq->charger_desc.name = bq->name;
bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
bq->charger_desc.properties = bq2415x_power_supply_props;
bq->charger_desc.num_properties =
ARRAY_SIZE(bq2415x_power_supply_props);
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
ret = bq2415x_detect_chip(bq);
if (ret < 0)
chip = BQUNKNOWN;
else
chip = ret;
ret = bq2415x_detect_revision(bq);
if (ret < 0)
strcpy(revstr, "unknown");
else
sprintf(revstr, "1.%d", ret);
bq->model = kasprintf(GFP_KERNEL,
"chip %s, revision %s, vender code %.3d",
bq2415x_chip_name[chip], revstr,
bq2415x_get_vender_code(bq));
if (!bq->model) {
dev_err(bq->dev, "failed to allocate model name\n");
return -ENOMEM;
}
bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
&psy_cfg);
if (IS_ERR(bq->charger)) {
kfree(bq->model);
return PTR_ERR(bq->charger);
}
return 0;
}
static void bq2415x_power_supply_exit(struct bq2415x_device *bq)
{
bq->autotimer = 0;
@ -1496,7 +1448,7 @@ static DEVICE_ATTR(charge_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static DEVICE_ATTR(boost_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static DEVICE_ATTR(fault_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static struct attribute *bq2415x_sysfs_attributes[] = {
static struct attribute *bq2415x_sysfs_attrs[] = {
/*
* TODO: some (appropriate) of these attrs should be switched to
* use power supply class props.
@ -1525,19 +1477,55 @@ static struct attribute *bq2415x_sysfs_attributes[] = {
NULL,
};
static const struct attribute_group bq2415x_sysfs_attr_group = {
.attrs = bq2415x_sysfs_attributes,
};
ATTRIBUTE_GROUPS(bq2415x_sysfs);
static int bq2415x_sysfs_init(struct bq2415x_device *bq)
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
{
return sysfs_create_group(&bq->charger->dev.kobj,
&bq2415x_sysfs_attr_group);
}
int ret;
int chip;
char revstr[8];
struct power_supply_config psy_cfg = {
.drv_data = bq,
.of_node = bq->dev->of_node,
.attr_grp = bq2415x_sysfs_groups,
};
static void bq2415x_sysfs_exit(struct bq2415x_device *bq)
{
sysfs_remove_group(&bq->charger->dev.kobj, &bq2415x_sysfs_attr_group);
bq->charger_desc.name = bq->name;
bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
bq->charger_desc.properties = bq2415x_power_supply_props;
bq->charger_desc.num_properties =
ARRAY_SIZE(bq2415x_power_supply_props);
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
ret = bq2415x_detect_chip(bq);
if (ret < 0)
chip = BQUNKNOWN;
else
chip = ret;
ret = bq2415x_detect_revision(bq);
if (ret < 0)
strcpy(revstr, "unknown");
else
sprintf(revstr, "1.%d", ret);
bq->model = kasprintf(GFP_KERNEL,
"chip %s, revision %s, vender code %.3d",
bq2415x_chip_name[chip], revstr,
bq2415x_get_vender_code(bq));
if (!bq->model) {
dev_err(bq->dev, "failed to allocate model name\n");
return -ENOMEM;
}
bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
&psy_cfg);
if (IS_ERR(bq->charger)) {
kfree(bq->model);
return PTR_ERR(bq->charger);
}
return 0;
}
/* main bq2415x probe function */
@ -1651,16 +1639,10 @@ static int bq2415x_probe(struct i2c_client *client,
goto error_2;
}
ret = bq2415x_sysfs_init(bq);
if (ret) {
dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret);
goto error_3;
}
ret = bq2415x_set_defaults(bq);
if (ret) {
dev_err(bq->dev, "failed to set default values: %d\n", ret);
goto error_4;
goto error_3;
}
if (bq->notify_node || bq->init_data.notify_device) {
@ -1668,7 +1650,7 @@ static int bq2415x_probe(struct i2c_client *client,
ret = power_supply_reg_notifier(&bq->nb);
if (ret) {
dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
goto error_4;
goto error_3;
}
bq->automode = 1;
@ -1707,8 +1689,6 @@ static int bq2415x_probe(struct i2c_client *client,
dev_info(bq->dev, "driver registered\n");
return 0;
error_4:
bq2415x_sysfs_exit(bq);
error_3:
bq2415x_power_supply_exit(bq);
error_2:
@ -1733,7 +1713,6 @@ static int bq2415x_remove(struct i2c_client *client)
power_supply_unreg_notifier(&bq->nb);
of_node_put(bq->notify_node);
bq2415x_sysfs_exit(bq);
bq2415x_power_supply_exit(bq);
bq2415x_reset_chip(bq);

View file

@ -21,6 +21,7 @@
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/extcon-provider.h>
#define BQ24190_MANUFACTURER "Texas Instruments"
@ -142,7 +143,7 @@
#define BQ24190_REG_VPRS_PN_MASK (BIT(5) | BIT(4) | BIT(3))
#define BQ24190_REG_VPRS_PN_SHIFT 3
#define BQ24190_REG_VPRS_PN_24190 0x4
#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193 */
#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193, 24196 */
#define BQ24190_REG_VPRS_PN_24192I 0x3
#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2)
#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2
@ -159,6 +160,7 @@
struct bq24190_dev_info {
struct i2c_client *client;
struct device *dev;
struct extcon_dev *edev;
struct power_supply *charger;
struct power_supply *battery;
struct delayed_work input_current_limit_work;
@ -174,6 +176,11 @@ struct bq24190_dev_info {
u8 watchdog;
};
static const unsigned int bq24190_usb_extcon_cable[] = {
EXTCON_USB,
EXTCON_NONE,
};
/*
* The tables below provide a 2-way mapping for the value that goes in
* the register field and the real-world value that it represents.
@ -402,9 +409,7 @@ static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
static struct attribute *
bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
static const struct attribute_group bq24190_sysfs_attr_group = {
.attrs = bq24190_sysfs_attrs,
};
ATTRIBUTE_GROUPS(bq24190_sysfs);
static void bq24190_sysfs_init_attrs(void)
{
@ -491,26 +496,6 @@ static ssize_t bq24190_sysfs_store(struct device *dev,
return count;
}
static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
{
bq24190_sysfs_init_attrs();
return sysfs_create_group(&bdi->charger->dev.kobj,
&bq24190_sysfs_attr_group);
}
static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
{
sysfs_remove_group(&bdi->charger->dev.kobj, &bq24190_sysfs_attr_group);
}
#else
static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
{
return 0;
}
static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
#endif
#ifdef CONFIG_REGULATOR
@ -577,6 +562,7 @@ static const struct regulator_ops bq24190_vbus_ops = {
static const struct regulator_desc bq24190_vbus_desc = {
.name = "usb_otg_vbus",
.of_match = "usb-otg-vbus",
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.ops = &bq24190_vbus_ops,
@ -1527,6 +1513,20 @@ static const struct power_supply_desc bq24190_battery_desc = {
.property_is_writeable = bq24190_battery_property_is_writeable,
};
static int bq24190_configure_usb_otg(struct bq24190_dev_info *bdi, u8 ss_reg)
{
bool otg_enabled;
int ret;
otg_enabled = !!(ss_reg & BQ24190_REG_SS_VBUS_STAT_MASK);
ret = extcon_set_state_sync(bdi->edev, EXTCON_USB, otg_enabled);
if (ret < 0)
dev_err(bdi->dev, "Can't set extcon state to %d: %d\n",
otg_enabled, ret);
return ret;
}
static void bq24190_check_status(struct bq24190_dev_info *bdi)
{
const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
@ -1596,8 +1596,10 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi)
bdi->ss_reg = ss_reg;
}
if (alert_charger || alert_battery)
if (alert_charger || alert_battery) {
power_supply_changed(bdi->charger);
bq24190_configure_usb_otg(bdi, ss_reg);
}
if (alert_battery && bdi->battery)
power_supply_changed(bdi->battery);
@ -1637,8 +1639,12 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
if (ret < 0)
return ret;
if (v != BQ24190_REG_VPRS_PN_24190 &&
v != BQ24190_REG_VPRS_PN_24192I) {
switch (v) {
case BQ24190_REG_VPRS_PN_24190:
case BQ24190_REG_VPRS_PN_24192:
case BQ24190_REG_VPRS_PN_24192I:
break;
default:
dev_err(bdi->dev, "Error unknown model: 0x%02x\n", v);
return -ENODEV;
}
@ -1727,6 +1733,14 @@ static int bq24190_probe(struct i2c_client *client,
return -EINVAL;
}
bdi->edev = devm_extcon_dev_allocate(dev, bq24190_usb_extcon_cable);
if (IS_ERR(bdi->edev))
return PTR_ERR(bdi->edev);
ret = devm_extcon_dev_register(dev, bdi->edev);
if (ret < 0)
return ret;
pm_runtime_enable(dev);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 600);
@ -1736,6 +1750,11 @@ static int bq24190_probe(struct i2c_client *client,
goto out_pmrt;
}
#ifdef CONFIG_SYSFS
bq24190_sysfs_init_attrs();
charger_cfg.attr_grp = bq24190_sysfs_groups;
#endif
charger_cfg.drv_data = bdi;
charger_cfg.of_node = dev->of_node;
charger_cfg.supplied_to = bq24190_charger_supplied_to;
@ -1773,11 +1792,9 @@ static int bq24190_probe(struct i2c_client *client,
goto out_charger;
}
ret = bq24190_sysfs_create_group(bdi);
if (ret < 0) {
dev_err(dev, "Can't create sysfs entries\n");
ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg);
if (ret < 0)
goto out_charger;
}
bdi->initialized = true;
@ -1787,12 +1804,12 @@ static int bq24190_probe(struct i2c_client *client,
"bq24190-charger", bdi);
if (ret < 0) {
dev_err(dev, "Can't set up irq handler\n");
goto out_sysfs;
goto out_charger;
}
ret = bq24190_register_vbus_regulator(bdi);
if (ret < 0)
goto out_sysfs;
goto out_charger;
enable_irq_wake(client->irq);
@ -1801,9 +1818,6 @@ static int bq24190_probe(struct i2c_client *client,
return 0;
out_sysfs:
bq24190_sysfs_remove_group(bdi);
out_charger:
if (!IS_ERR_OR_NULL(bdi->battery))
power_supply_unregister(bdi->battery);
@ -1828,7 +1842,6 @@ static int bq24190_remove(struct i2c_client *client)
}
bq24190_register_reset(bdi);
bq24190_sysfs_remove_group(bdi);
if (bdi->battery)
power_supply_unregister(bdi->battery);
power_supply_unregister(bdi->charger);
@ -1931,7 +1944,9 @@ static const struct dev_pm_ops bq24190_pm_ops = {
static const struct i2c_device_id bq24190_i2c_ids[] = {
{ "bq24190" },
{ "bq24192" },
{ "bq24192i" },
{ "bq24196" },
{ },
};
MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
@ -1939,7 +1954,9 @@ MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
#ifdef CONFIG_OF
static const struct of_device_id bq24190_of_match[] = {
{ .compatible = "ti,bq24190", },
{ .compatible = "ti,bq24192", },
{ .compatible = "ti,bq24192i", },
{ .compatible = "ti,bq24196", },
{ },
};
MODULE_DEVICE_TABLE(of, bq24190_of_match);

View file

@ -845,7 +845,7 @@ static DEVICE_ATTR(high_impedance_enable, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(sysoff_enable, S_IWUSR | S_IRUGO,
bq24257_sysfs_show_enable, bq24257_sysfs_set_enable);
static struct attribute *bq24257_charger_attr[] = {
static struct attribute *bq24257_charger_sysfs_attrs[] = {
&dev_attr_ovp_voltage.attr,
&dev_attr_in_dpm_voltage.attr,
&dev_attr_high_impedance_enable.attr,
@ -853,14 +853,13 @@ static struct attribute *bq24257_charger_attr[] = {
NULL,
};
static const struct attribute_group bq24257_attr_group = {
.attrs = bq24257_charger_attr,
};
ATTRIBUTE_GROUPS(bq24257_charger_sysfs);
static int bq24257_power_supply_init(struct bq24257_device *bq)
{
struct power_supply_config psy_cfg = { .drv_data = bq, };
psy_cfg.attr_grp = bq24257_charger_sysfs_groups;
psy_cfg.supplied_to = bq24257_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq24257_charger_supplied_to);
@ -1084,12 +1083,6 @@ static int bq24257_probe(struct i2c_client *client,
return ret;
}
ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
if (ret < 0) {
dev_err(dev, "Can't create sysfs entries\n");
return ret;
}
return 0;
}
@ -1100,8 +1093,6 @@ static int bq24257_remove(struct i2c_client *client)
if (bq->iilimit_autoset_enable)
cancel_delayed_work_sync(&bq->iilimit_setup_work);
sysfs_remove_group(&bq->charger->dev.kobj, &bq24257_attr_group);
bq24257_field_write(bq, F_RESET, 1); /* reset to defaults */
return 0;

View file

@ -183,7 +183,7 @@ static const struct reg_field bq25890_reg_fields[] = {
[F_CHG_TMR] = REG_FIELD(0x07, 1, 2),
[F_JEITA_ISET] = REG_FIELD(0x07, 0, 0),
/* REG08 */
[F_BATCMP] = REG_FIELD(0x08, 6, 7), // 5-7 on BQ25896
[F_BATCMP] = REG_FIELD(0x08, 5, 7),
[F_VCLAMP] = REG_FIELD(0x08, 2, 4),
[F_TREG] = REG_FIELD(0x08, 0, 1),
/* REG09 */

View file

@ -363,7 +363,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
int err = 0, i;
struct charger_desc *desc = cm->desc;
/* Ignore if it's redundent command */
/* Ignore if it's redundant command */
if (enable == cm->charger_enabled)
return 0;
@ -1212,7 +1212,6 @@ static int charger_extcon_init(struct charger_manager *cm,
if (ret < 0) {
pr_info("Cannot register extcon_dev for %s(cable: %s)\n",
cable->extcon_name, cable->name);
ret = -EINVAL;
}
return ret;
@ -1352,7 +1351,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
}
/**
* charger_manager_register_sysfs - Register sysfs entry for each charger
* charger_manager_prepare_sysfs - Prepare sysfs entry for each charger
* @cm: the Charger Manager representing the battery.
*
* This function add sysfs entry for charger(regulator) to control charger from
@ -1364,34 +1363,30 @@ static ssize_t charger_externally_control_store(struct device *dev,
* externally_control, this charger isn't controlled from charger-manager and
* always stay off state of regulator.
*/
static int charger_manager_register_sysfs(struct charger_manager *cm)
static int charger_manager_prepare_sysfs(struct charger_manager *cm)
{
struct charger_desc *desc = cm->desc;
struct charger_regulator *charger;
int chargers_externally_control = 1;
char buf[11];
char *str;
int ret;
char *name;
int i;
/* Create sysfs entry to control charger(regulator) */
for (i = 0; i < desc->num_charger_regulators; i++) {
charger = &desc->charger_regulators[i];
snprintf(buf, 10, "charger.%d", i);
str = devm_kzalloc(cm->dev,
strlen(buf) + 1, GFP_KERNEL);
if (!str)
name = devm_kasprintf(cm->dev, GFP_KERNEL, "charger.%d", i);
if (!name)
return -ENOMEM;
strcpy(str, buf);
charger->attrs[0] = &charger->attr_name.attr;
charger->attrs[1] = &charger->attr_state.attr;
charger->attrs[2] = &charger->attr_externally_control.attr;
charger->attrs[3] = NULL;
charger->attr_g.name = str;
charger->attr_g.attrs = charger->attrs;
charger->attr_grp.name = name;
charger->attr_grp.attrs = charger->attrs;
desc->sysfs_groups[i] = &charger->attr_grp;
sysfs_attr_init(&charger->attr_name.attr);
charger->attr_name.attr.name = "name";
@ -1418,14 +1413,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
dev_info(cm->dev, "'%s' regulator's externally_control is %d\n",
charger->regulator_name, charger->externally_control);
ret = sysfs_create_group(&cm->charger_psy->dev.kobj,
&charger->attr_g);
if (ret < 0) {
dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n",
charger->regulator_name);
return ret;
}
}
if (chargers_externally_control) {
@ -1521,19 +1508,19 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
/* chargers */
of_property_read_u32(np, "cm-num-chargers", &num_chgs);
if (num_chgs) {
int i;
/* Allocate empty bin at the tail of array */
desc->psy_charger_stat = devm_kcalloc(dev,
num_chgs + 1,
sizeof(char *),
GFP_KERNEL);
if (desc->psy_charger_stat) {
int i;
for (i = 0; i < num_chgs; i++)
of_property_read_string_index(np, "cm-chargers",
i, &desc->psy_charger_stat[i]);
} else {
if (!desc->psy_charger_stat)
return ERR_PTR(-ENOMEM);
}
for (i = 0; i < num_chgs; i++)
of_property_read_string_index(np, "cm-chargers",
i, &desc->psy_charger_stat[i]);
}
of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge);
@ -1566,6 +1553,13 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
desc->charger_regulators = chg_regs;
desc->sysfs_groups = devm_kcalloc(dev,
desc->num_charger_regulators + 1,
sizeof(*desc->sysfs_groups),
GFP_KERNEL);
if (!desc->sysfs_groups)
return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
struct charger_cable *cables;
struct device_node *_child;
@ -1633,7 +1627,7 @@ static int charger_manager_probe(struct platform_device *pdev)
if (IS_ERR(desc)) {
dev_err(&pdev->dev, "No platform data (desc) found\n");
return -ENODEV;
return PTR_ERR(desc);
}
cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL);
@ -1687,10 +1681,6 @@ static int charger_manager_probe(struct platform_device *pdev)
return -EINVAL;
}
/* Counting index only */
while (desc->psy_charger_stat[i])
i++;
/* Check if charger's supplies are present at probe */
for (i = 0; desc->psy_charger_stat[i]; i++) {
struct power_supply *psy;
@ -1772,6 +1762,15 @@ static int charger_manager_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
/* Register sysfs entry for charger(regulator) */
ret = charger_manager_prepare_sysfs(cm);
if (ret < 0) {
dev_err(&pdev->dev,
"Cannot prepare sysfs entry of regulators\n");
return ret;
}
psy_cfg.attr_grp = desc->sysfs_groups;
cm->charger_psy = power_supply_register(&pdev->dev,
&cm->charger_psy_desc,
&psy_cfg);
@ -1788,14 +1787,6 @@ static int charger_manager_probe(struct platform_device *pdev)
goto err_reg_extcon;
}
/* Register sysfs entry for charger(regulator) */
ret = charger_manager_register_sysfs(cm);
if (ret < 0) {
dev_err(&pdev->dev,
"Cannot initialize sysfs entry of regulator\n");
goto err_reg_sysfs;
}
/* Add to the list */
mutex_lock(&cm_list_mtx);
list_add(&cm->entry, &cm_list);
@ -1803,7 +1794,7 @@ static int charger_manager_probe(struct platform_device *pdev)
/*
* Charger-manager is capable of waking up the systme from sleep
* when event is happend through cm_notify_event()
* when event is happened through cm_notify_event()
*/
device_init_wakeup(&pdev->dev, true);
device_set_wakeup_capable(&pdev->dev, false);
@ -1819,14 +1810,6 @@ static int charger_manager_probe(struct platform_device *pdev)
return 0;
err_reg_sysfs:
for (i = 0; i < desc->num_charger_regulators; i++) {
struct charger_regulator *charger;
charger = &desc->charger_regulators[i];
sysfs_remove_group(&cm->charger_psy->dev.kobj,
&charger->attr_g);
}
err_reg_extcon:
for (i = 0; i < desc->num_charger_regulators; i++) {
struct charger_regulator *charger;
@ -2023,7 +2006,7 @@ module_exit(charger_manager_cleanup);
* cm_notify_event - charger driver notify Charger Manager of charger event
* @psy: pointer to instance of charger's power_supply
* @type: type of charger event
* @msg: optional message passed to uevent_notify fuction
* @msg: optional message passed to uevent_notify function
*/
void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
char *msg)

View file

@ -620,7 +620,7 @@ static int cpcap_battery_init_irq(struct platform_device *pdev,
static int cpcap_battery_init_interrupts(struct platform_device *pdev,
struct cpcap_battery_ddata *ddata)
{
const char * const cpcap_battery_irqs[] = {
static const char * const cpcap_battery_irqs[] = {
"eol", "lowbph", "lowbpl",
"chrgcurr1", "battdetb"
};

View file

@ -544,7 +544,7 @@ static void cpcap_charger_init_optional_gpios(struct cpcap_charger_ddata *ddata)
if (IS_ERR(ddata->gpio[i])) {
dev_info(ddata->dev, "no mode change GPIO%i: %li\n",
i, PTR_ERR(ddata->gpio[i]));
ddata->gpio[i] = NULL;
ddata->gpio[i] = NULL;
}
}
}

View file

@ -658,7 +658,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
return count;
}
static const struct bin_attribute ds2780_param_eeprom_bin_attr = {
static struct bin_attribute ds2780_param_eeprom_bin_attr = {
.attr = {
.name = "param_eeprom",
.mode = S_IRUGO | S_IWUSR,
@ -703,7 +703,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
return count;
}
static const struct bin_attribute ds2780_user_eeprom_bin_attr = {
static struct bin_attribute ds2780_user_eeprom_bin_attr = {
.attr = {
.name = "user_eeprom",
.mode = S_IRUGO | S_IWUSR,
@ -722,8 +722,7 @@ static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting,
static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin,
ds2780_set_pio_pin);
static struct attribute *ds2780_attributes[] = {
static struct attribute *ds2780_sysfs_attrs[] = {
&dev_attr_pmod_enabled.attr,
&dev_attr_sense_resistor_value.attr,
&dev_attr_rsgain_setting.attr,
@ -731,21 +730,30 @@ static struct attribute *ds2780_attributes[] = {
NULL
};
static const struct attribute_group ds2780_attr_group = {
.attrs = ds2780_attributes,
static struct bin_attribute *ds2780_sysfs_bin_attrs[] = {
&ds2780_param_eeprom_bin_attr,
&ds2780_user_eeprom_bin_attr,
NULL
};
static const struct attribute_group ds2780_sysfs_group = {
.attrs = ds2780_sysfs_attrs,
.bin_attrs = ds2780_sysfs_bin_attrs,
};
static const struct attribute_group *ds2780_sysfs_groups[] = {
&ds2780_sysfs_group,
NULL,
};
static int ds2780_battery_probe(struct platform_device *pdev)
{
struct power_supply_config psy_cfg = {};
int ret = 0;
struct ds2780_device_info *dev_info;
dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL);
if (!dev_info) {
ret = -ENOMEM;
goto fail;
}
if (!dev_info)
return -ENOMEM;
platform_set_drvdata(pdev, dev_info);
@ -758,62 +766,16 @@ static int ds2780_battery_probe(struct platform_device *pdev)
dev_info->bat_desc.get_property = ds2780_battery_get_property;
psy_cfg.drv_data = dev_info;
psy_cfg.attr_grp = ds2780_sysfs_groups;
dev_info->bat = power_supply_register(&pdev->dev, &dev_info->bat_desc,
&psy_cfg);
dev_info->bat = devm_power_supply_register(&pdev->dev,
&dev_info->bat_desc,
&psy_cfg);
if (IS_ERR(dev_info->bat)) {
dev_err(dev_info->dev, "failed to register battery\n");
ret = PTR_ERR(dev_info->bat);
goto fail;
return PTR_ERR(dev_info->bat);
}
ret = sysfs_create_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
if (ret) {
dev_err(dev_info->dev, "failed to create sysfs group\n");
goto fail_unregister;
}
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
&ds2780_param_eeprom_bin_attr);
if (ret) {
dev_err(dev_info->dev,
"failed to create param eeprom bin file");
goto fail_remove_group;
}
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
&ds2780_user_eeprom_bin_attr);
if (ret) {
dev_err(dev_info->dev,
"failed to create user eeprom bin file");
goto fail_remove_bin_file;
}
return 0;
fail_remove_bin_file:
sysfs_remove_bin_file(&dev_info->bat->dev.kobj,
&ds2780_param_eeprom_bin_attr);
fail_remove_group:
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
fail_unregister:
power_supply_unregister(dev_info->bat);
fail:
return ret;
}
static int ds2780_battery_remove(struct platform_device *pdev)
{
struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
/*
* Remove attributes before unregistering power supply
* because 'bat' will be freed on power_supply_unregister() call.
*/
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
power_supply_unregister(dev_info->bat);
return 0;
}
@ -822,7 +784,6 @@ static struct platform_driver ds2780_battery_driver = {
.name = "ds2780-battery",
},
.probe = ds2780_battery_probe,
.remove = ds2780_battery_remove,
};
module_platform_driver(ds2780_battery_driver);

View file

@ -660,7 +660,7 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp,
return count;
}
static const struct bin_attribute ds2781_param_eeprom_bin_attr = {
static struct bin_attribute ds2781_param_eeprom_bin_attr = {
.attr = {
.name = "param_eeprom",
.mode = S_IRUGO | S_IWUSR,
@ -706,7 +706,7 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp,
return count;
}
static const struct bin_attribute ds2781_user_eeprom_bin_attr = {
static struct bin_attribute ds2781_user_eeprom_bin_attr = {
.attr = {
.name = "user_eeprom",
.mode = S_IRUGO | S_IWUSR,
@ -725,8 +725,7 @@ static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2781_get_rsgain_setting,
static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2781_get_pio_pin,
ds2781_set_pio_pin);
static struct attribute *ds2781_attributes[] = {
static struct attribute *ds2781_sysfs_attrs[] = {
&dev_attr_pmod_enabled.attr,
&dev_attr_sense_resistor_value.attr,
&dev_attr_rsgain_setting.attr,
@ -734,14 +733,26 @@ static struct attribute *ds2781_attributes[] = {
NULL
};
static const struct attribute_group ds2781_attr_group = {
.attrs = ds2781_attributes,
static struct bin_attribute *ds2781_sysfs_bin_attrs[] = {
&ds2781_param_eeprom_bin_attr,
&ds2781_user_eeprom_bin_attr,
NULL,
};
static const struct attribute_group ds2781_sysfs_group = {
.attrs = ds2781_sysfs_attrs,
.bin_attrs = ds2781_sysfs_bin_attrs,
};
static const struct attribute_group *ds2781_sysfs_groups[] = {
&ds2781_sysfs_group,
NULL,
};
static int ds2781_battery_probe(struct platform_device *pdev)
{
struct power_supply_config psy_cfg = {};
int ret = 0;
struct ds2781_device_info *dev_info;
dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL);
@ -759,62 +770,16 @@ static int ds2781_battery_probe(struct platform_device *pdev)
dev_info->bat_desc.get_property = ds2781_battery_get_property;
psy_cfg.drv_data = dev_info;
psy_cfg.attr_grp = ds2781_sysfs_groups;
dev_info->bat = power_supply_register(&pdev->dev, &dev_info->bat_desc,
&psy_cfg);
dev_info->bat = devm_power_supply_register(&pdev->dev,
&dev_info->bat_desc,
&psy_cfg);
if (IS_ERR(dev_info->bat)) {
dev_err(dev_info->dev, "failed to register battery\n");
ret = PTR_ERR(dev_info->bat);
goto fail;
return PTR_ERR(dev_info->bat);
}
ret = sysfs_create_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
if (ret) {
dev_err(dev_info->dev, "failed to create sysfs group\n");
goto fail_unregister;
}
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
&ds2781_param_eeprom_bin_attr);
if (ret) {
dev_err(dev_info->dev,
"failed to create param eeprom bin file");
goto fail_remove_group;
}
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
&ds2781_user_eeprom_bin_attr);
if (ret) {
dev_err(dev_info->dev,
"failed to create user eeprom bin file");
goto fail_remove_bin_file;
}
return 0;
fail_remove_bin_file:
sysfs_remove_bin_file(&dev_info->bat->dev.kobj,
&ds2781_param_eeprom_bin_attr);
fail_remove_group:
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
fail_unregister:
power_supply_unregister(dev_info->bat);
fail:
return ret;
}
static int ds2781_battery_remove(struct platform_device *pdev)
{
struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
/*
* Remove attributes before unregistering power supply
* because 'bat' will be freed on power_supply_unregister() call.
*/
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
power_supply_unregister(dev_info->bat);
return 0;
}
@ -823,7 +788,6 @@ static struct platform_driver ds2781_battery_driver = {
.name = "ds2781-battery",
},
.probe = ds2781_battery_probe,
.remove = ds2781_battery_remove,
};
module_platform_driver(ds2781_battery_driver);

View file

@ -82,11 +82,11 @@ static enum power_supply_type gpio_charger_get_type(struct device *dev)
if (!strcmp("usb-sdp", chargetype))
return POWER_SUPPLY_TYPE_USB;
if (!strcmp("usb-dcp", chargetype))
return POWER_SUPPLY_TYPE_USB_DCP;
return POWER_SUPPLY_TYPE_USB;
if (!strcmp("usb-cdp", chargetype))
return POWER_SUPPLY_TYPE_USB_CDP;
return POWER_SUPPLY_TYPE_USB;
if (!strcmp("usb-aca", chargetype))
return POWER_SUPPLY_TYPE_USB_ACA;
return POWER_SUPPLY_TYPE_USB;
}
dev_warn(dev, "unknown charger type %s\n", chargetype);

View file

@ -410,30 +410,6 @@ static const struct power_supply_desc lp8788_psy_battery_desc = {
.get_property = lp8788_battery_get_property,
};
static int lp8788_psy_register(struct platform_device *pdev,
struct lp8788_charger *pchg)
{
struct power_supply_config charger_cfg = {};
charger_cfg.supplied_to = battery_supplied_to;
charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);
pchg->charger = power_supply_register(&pdev->dev,
&lp8788_psy_charger_desc,
&charger_cfg);
if (IS_ERR(pchg->charger))
return -EPERM;
pchg->battery = power_supply_register(&pdev->dev,
&lp8788_psy_battery_desc, NULL);
if (IS_ERR(pchg->battery)) {
power_supply_unregister(pchg->charger);
return -EPERM;
}
return 0;
}
static void lp8788_psy_unregister(struct lp8788_charger *pchg)
{
power_supply_unregister(pchg->battery);
@ -690,16 +666,39 @@ static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);
static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);
static struct attribute *lp8788_charger_attr[] = {
static struct attribute *lp8788_charger_sysfs_attrs[] = {
&dev_attr_charger_status.attr,
&dev_attr_eoc_time.attr,
&dev_attr_eoc_level.attr,
NULL,
};
static const struct attribute_group lp8788_attr_group = {
.attrs = lp8788_charger_attr,
};
ATTRIBUTE_GROUPS(lp8788_charger_sysfs);
static int lp8788_psy_register(struct platform_device *pdev,
struct lp8788_charger *pchg)
{
struct power_supply_config charger_cfg = {};
charger_cfg.attr_grp = lp8788_charger_sysfs_groups;
charger_cfg.supplied_to = battery_supplied_to;
charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);
pchg->charger = power_supply_register(&pdev->dev,
&lp8788_psy_charger_desc,
&charger_cfg);
if (IS_ERR(pchg->charger))
return -EPERM;
pchg->battery = power_supply_register(&pdev->dev,
&lp8788_psy_battery_desc, NULL);
if (IS_ERR(pchg->battery)) {
power_supply_unregister(pchg->charger);
return -EPERM;
}
return 0;
}
static int lp8788_charger_probe(struct platform_device *pdev)
{
@ -726,12 +725,6 @@ static int lp8788_charger_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group);
if (ret) {
lp8788_psy_unregister(pchg);
return ret;
}
ret = lp8788_irq_register(pdev, pchg);
if (ret)
dev_warn(dev, "failed to register charger irq: %d\n", ret);
@ -745,7 +738,6 @@ static int lp8788_charger_remove(struct platform_device *pdev)
flush_work(&pchg->charger_work);
lp8788_irq_unregister(pdev, pchg);
sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group);
lp8788_psy_unregister(pchg);
lp8788_release_adc_channel(pchg);

View file

@ -428,14 +428,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
val->intval = (s16)be16_to_cpu(ec_word) * 10 / 256;
break;
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
val->intval = (int)be16_to_cpu(ec_word) * 10 / 256;
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);

View file

@ -245,17 +245,14 @@ static ssize_t set_chglim(struct device *dev,
*/
static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
static struct attribute *pcf50633_mbc_sysfs_entries[] = {
static struct attribute *pcf50633_mbc_sysfs_attrs[] = {
&dev_attr_chgmode.attr,
&dev_attr_usb_curlim.attr,
&dev_attr_chg_curlim.attr,
NULL,
};
static const struct attribute_group mbc_attr_group = {
.name = NULL, /* put in device directory */
.attrs = pcf50633_mbc_sysfs_entries,
};
ATTRIBUTE_GROUPS(pcf50633_mbc_sysfs);
static void
pcf50633_mbc_irq_handler(int irq, void *data)
@ -390,6 +387,7 @@ static const struct power_supply_desc pcf50633_mbc_ac_desc = {
static int pcf50633_mbc_probe(struct platform_device *pdev)
{
struct power_supply_config psy_cfg = {};
struct power_supply_config usb_psy_cfg;
struct pcf50633_mbc *mbc;
int i;
u8 mbcs1;
@ -419,8 +417,11 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
return PTR_ERR(mbc->adapter);
}
usb_psy_cfg = psy_cfg;
usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups;
mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc,
&psy_cfg);
&usb_psy_cfg);
if (IS_ERR(mbc->usb)) {
dev_err(mbc->pcf->dev, "failed to register usb\n");
power_supply_unregister(mbc->adapter);
@ -436,9 +437,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
return PTR_ERR(mbc->ac);
}
if (sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group))
dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
if (mbcs1 & PCF50633_MBCS1_USBPRES)
pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
@ -457,7 +455,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group);
power_supply_unregister(mbc->usb);
power_supply_unregister(mbc->adapter);
power_supply_unregister(mbc->ac);

View file

@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
{
struct device_node *battery_np;
const char *value;
int err;
int err, len, index;
info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL;
@ -579,6 +579,13 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->charge_term_current_ua = -EINVAL;
info->constant_charge_current_max_ua = -EINVAL;
info->constant_charge_voltage_max_uv = -EINVAL;
info->factory_internal_resistance_uohm = -EINVAL;
for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
info->ocv_table[index] = NULL;
info->ocv_temp[index] = -EINVAL;
info->ocv_table_size[index] = -EINVAL;
}
if (!psy->of_node) {
dev_warn(&psy->dev, "%s currently only supports devicetree\n",
@ -616,11 +623,142 @@ int power_supply_get_battery_info(struct power_supply *psy,
&info->constant_charge_current_max_ua);
of_property_read_u32(battery_np, "constant_charge_voltage_max_microvolt",
&info->constant_charge_voltage_max_uv);
of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms",
&info->factory_internal_resistance_uohm);
len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
if (len < 0 && len != -EINVAL) {
return len;
} else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
dev_err(&psy->dev, "Too many temperature values\n");
return -EINVAL;
} else if (len > 0) {
of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
info->ocv_temp, len);
}
for (index = 0; index < len; index++) {
struct power_supply_battery_ocv_table *table;
char *propname;
const __be32 *list;
int i, tab_len, size;
propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", index);
list = of_get_property(battery_np, propname, &size);
if (!list || !size) {
dev_err(&psy->dev, "failed to get %s\n", propname);
kfree(propname);
power_supply_put_battery_info(psy, info);
return -EINVAL;
}
kfree(propname);
tab_len = size / (2 * sizeof(__be32));
info->ocv_table_size[index] = tab_len;
table = info->ocv_table[index] =
devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL);
if (!info->ocv_table[index]) {
power_supply_put_battery_info(psy, info);
return -ENOMEM;
}
for (i = 0; i < tab_len; i++) {
table[i].ocv = be32_to_cpu(*list++);
table[i].capacity = be32_to_cpu(*list++);
}
}
return 0;
}
EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
void power_supply_put_battery_info(struct power_supply *psy,
struct power_supply_battery_info *info)
{
int i;
for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) {
if (info->ocv_table[i])
devm_kfree(&psy->dev, info->ocv_table[i]);
}
}
EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
/**
* power_supply_ocv2cap_simple() - find the battery capacity
* @table: Pointer to battery OCV lookup table
* @table_len: OCV table length
* @ocv: Current OCV value
*
* This helper function is used to look up battery capacity according to
* current OCV value from one OCV table, and the OCV table must be ordered
* descending.
*
* Return: the battery capacity.
*/
int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
int table_len, int ocv)
{
int i, cap, tmp;
for (i = 0; i < table_len; i++)
if (ocv > table[i].ocv)
break;
if (i > 0 && i < table_len) {
tmp = (table[i - 1].capacity - table[i].capacity) *
(ocv - table[i].ocv);
tmp /= table[i - 1].ocv - table[i].ocv;
cap = tmp + table[i].capacity;
} else if (i == 0) {
cap = table[0].capacity;
} else {
cap = table[table_len - 1].capacity;
}
return cap;
}
EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple);
struct power_supply_battery_ocv_table *
power_supply_find_ocv2cap_table(struct power_supply_battery_info *info,
int temp, int *table_len)
{
int best_temp_diff = INT_MAX, temp_diff;
u8 i, best_index = 0;
if (!info->ocv_table[0])
return NULL;
for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) {
temp_diff = abs(info->ocv_temp[i] - temp);
if (temp_diff < best_temp_diff) {
best_temp_diff = temp_diff;
best_index = i;
}
}
*table_len = info->ocv_table_size[best_index];
return info->ocv_table[best_index];
}
EXPORT_SYMBOL_GPL(power_supply_find_ocv2cap_table);
int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info,
int ocv, int temp)
{
struct power_supply_battery_ocv_table *table;
int table_len;
table = power_supply_find_ocv2cap_table(info, temp, &table_len);
if (!table)
return -EINVAL;
return power_supply_ocv2cap_simple(table, table_len, ocv);
}
EXPORT_SYMBOL_GPL(power_supply_batinfo_ocv2cap);
int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@ -880,6 +1018,7 @@ __power_supply_register(struct device *parent,
dev_set_drvdata(dev, psy);
psy->desc = desc;
if (cfg) {
dev->groups = cfg->attr_grp;
psy->drv_data = cfg->drv_data;
psy->of_node =
cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node;

View file

@ -57,9 +57,11 @@ struct sc2731_charger_info {
struct usb_phy *usb_phy;
struct notifier_block usb_notify;
struct power_supply *psy_usb;
struct work_struct work;
struct mutex lock;
bool charging;
u32 base;
u32 limit;
};
static void sc2731_charger_stop_charge(struct sc2731_charger_info *info)
@ -318,22 +320,21 @@ static const struct power_supply_desc sc2731_charger_desc = {
.property_is_writeable = sc2731_charger_property_is_writeable,
};
static int sc2731_charger_usb_change(struct notifier_block *nb,
unsigned long limit, void *data)
static void sc2731_charger_work(struct work_struct *data)
{
struct sc2731_charger_info *info =
container_of(nb, struct sc2731_charger_info, usb_notify);
int ret = 0;
container_of(data, struct sc2731_charger_info, work);
int ret;
mutex_lock(&info->lock);
if (limit > 0) {
if (info->limit > 0 && !info->charging) {
/* set current limitation and start to charge */
ret = sc2731_charger_set_current_limit(info, limit);
ret = sc2731_charger_set_current_limit(info, info->limit);
if (ret)
goto out;
ret = sc2731_charger_set_current(info, limit);
ret = sc2731_charger_set_current(info, info->limit);
if (ret)
goto out;
@ -342,7 +343,7 @@ static int sc2731_charger_usb_change(struct notifier_block *nb,
goto out;
info->charging = true;
} else {
} else if (!info->limit && info->charging) {
/* Stop charging */
info->charging = false;
sc2731_charger_stop_charge(info);
@ -350,7 +351,19 @@ static int sc2731_charger_usb_change(struct notifier_block *nb,
out:
mutex_unlock(&info->lock);
return ret;
}
static int sc2731_charger_usb_change(struct notifier_block *nb,
unsigned long limit, void *data)
{
struct sc2731_charger_info *info =
container_of(nb, struct sc2731_charger_info, usb_notify);
info->limit = limit;
schedule_work(&info->work);
return NOTIFY_OK;
}
static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
@ -395,6 +408,8 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
vol_val = (term_voltage - 4200) / 100;
else
vol_val = 0;
power_supply_put_battery_info(info->psy_usb, &bat_info);
}
/* Set charge termination current */
@ -419,6 +434,24 @@ error:
return ret;
}
static void sc2731_charger_detect_status(struct sc2731_charger_info *info)
{
unsigned int min, max;
/*
* If the USB charger status has been USB_CHARGER_PRESENT before
* registering the notifier, we should start to charge with getting
* the charge current.
*/
if (info->usb_phy->chg_state != USB_CHARGER_PRESENT)
return;
usb_phy_get_charger_current(info->usb_phy, &min, &max);
info->limit = min;
schedule_work(&info->work);
}
static int sc2731_charger_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@ -432,6 +465,7 @@ static int sc2731_charger_probe(struct platform_device *pdev)
mutex_init(&info->lock);
info->dev = &pdev->dev;
INIT_WORK(&info->work, sc2731_charger_work);
info->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!info->regmap) {
@ -472,6 +506,8 @@ static int sc2731_charger_probe(struct platform_device *pdev)
return ret;
}
sc2731_charger_detect_status(info);
return 0;
}

File diff suppressed because it is too large Load diff