From e771e0a1e4d5566c857ad312de3fd95b955df871 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 30 Mar 2016 09:49:48 +0900 Subject: power: reset: keystone: Enable COMPILE_TEST Enable the COMPILE_TEST to get build coverage, except on platforms !HAS_IOMEM (required by selected MFD_SYSCON). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 9bb2622c23bf..0cc8fc97e14d 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -148,7 +148,8 @@ config POWER_RESET_XGENE config POWER_RESET_KEYSTONE bool "Keystone reset driver" - depends on ARCH_KEYSTONE + depends on ARCH_KEYSTONE || COMPILE_TEST + depends on HAS_IOMEM select MFD_SYSCON help Reboot support for the KEYSTONE SoCs. -- cgit v1.2.3 From 5d9e01b31dc06a466ef2d35620d93a6c9941b387 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 31 May 2016 13:44:58 -0500 Subject: power_supply: bq27xxx_battery: Fix copy/paste error in header comment Signed-off-by: Andrew F. Davis Signed-off-by: Sebastian Reichel --- drivers/power/bq27xxx_battery_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/bq27xxx_battery_i2c.c b/drivers/power/bq27xxx_battery_i2c.c index b8f8d3ade31b..85d4ea2a9c20 100644 --- a/drivers/power/bq27xxx_battery_i2c.c +++ b/drivers/power/bq27xxx_battery_i2c.c @@ -1,5 +1,5 @@ /* - * SCI Reset driver for Keystone based devices + * BQ27xxx battery monitor I2C driver * * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis -- cgit v1.2.3 From 5630b4334c676ff60d9613e7b6a4cc89cb562acb Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 31 May 2016 13:44:59 -0500 Subject: power_supply: bq27xxx_battery: Index register numbers by enum Currently we use tables to map from register function to register number, these tables assume the enum used to describe the register function and index the register number is ordered to match the enum order. Index the register numbers by the enum instead. This also removes the need to comment each value with its function. Signed-off-by: Andrew F. Davis Signed-off-by: Sebastian Reichel --- drivers/power/bq27xxx_battery.c | 238 ++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 119 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c index 45f6ebf88df6..01737fab0048 100644 --- a/drivers/power/bq27xxx_battery.c +++ b/drivers/power/bq27xxx_battery.c @@ -104,143 +104,143 @@ enum bq27xxx_reg_index { /* Register mappings */ static u8 bq27000_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - INVALID_REG_ADDR, /* INT TEMP - NA*/ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - 0x18, /* TTF */ - 0x1c, /* TTES */ - 0x26, /* TTECP */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - 0x22, /* AE */ - 0x0b, /* SOC(RSOC) */ - 0x76, /* DCAP(ILMD) */ - 0x24, /* AP */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x0b, + [BQ27XXX_REG_DCAP] = 0x76, + [BQ27XXX_REG_AP] = 0x24, }; static u8 bq27010_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - INVALID_REG_ADDR, /* INT TEMP - NA*/ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - 0x18, /* TTF */ - 0x1c, /* TTES */ - 0x26, /* TTECP */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - INVALID_REG_ADDR, /* AE - NA */ - 0x0b, /* SOC(RSOC) */ - 0x76, /* DCAP(ILMD) */ - INVALID_REG_ADDR, /* AP - NA */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x0b, + [BQ27XXX_REG_DCAP] = 0x76, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }; static u8 bq27500_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - 0x28, /* INT TEMP */ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - INVALID_REG_ADDR, /* TTF - NA */ - 0x1a, /* TTES */ - INVALID_REG_ADDR, /* TTECP - NA */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - INVALID_REG_ADDR, /* AE - NA */ - 0x2c, /* SOC(RSOC) */ - 0x3c, /* DCAP(ILMD) */ - INVALID_REG_ADDR, /* AP - NA */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1a, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }; static u8 bq27530_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - 0x32, /* INT TEMP */ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - INVALID_REG_ADDR, /* TTF - NA */ - INVALID_REG_ADDR, /* TTES - NA */ - INVALID_REG_ADDR, /* TTECP - NA */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - INVALID_REG_ADDR, /* AE - NA */ - 0x2c, /* SOC(RSOC) */ - INVALID_REG_ADDR, /* DCAP - NA */ - 0x24, /* AP */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x32, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = 0x24, }; static u8 bq27541_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - 0x28, /* INT TEMP */ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - INVALID_REG_ADDR, /* TTF - NA */ - INVALID_REG_ADDR, /* TTES - NA */ - INVALID_REG_ADDR, /* TTECP - NA */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - INVALID_REG_ADDR, /* AE - NA */ - 0x2c, /* SOC(RSOC) */ - 0x3c, /* DCAP */ - 0x24, /* AP */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, }; static u8 bq27545_regs[] = { - 0x00, /* CONTROL */ - 0x06, /* TEMP */ - 0x28, /* INT TEMP */ - 0x08, /* VOLT */ - 0x14, /* AVG CURR */ - 0x0a, /* FLAGS */ - 0x16, /* TTE */ - INVALID_REG_ADDR, /* TTF - NA */ - INVALID_REG_ADDR, /* TTES - NA */ - INVALID_REG_ADDR, /* TTECP - NA */ - 0x0c, /* NAC */ - 0x12, /* LMD(FCC) */ - 0x2a, /* CYCT */ - INVALID_REG_ADDR, /* AE - NA */ - 0x2c, /* SOC(RSOC) */ - INVALID_REG_ADDR, /* DCAP - NA */ - 0x24, /* AP */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = 0x24, }; static u8 bq27421_regs[] = { - 0x00, /* CONTROL */ - 0x02, /* TEMP */ - 0x1e, /* INT TEMP */ - 0x04, /* VOLT */ - 0x10, /* AVG CURR */ - 0x06, /* FLAGS */ - INVALID_REG_ADDR, /* TTE - NA */ - INVALID_REG_ADDR, /* TTF - NA */ - INVALID_REG_ADDR, /* TTES - NA */ - INVALID_REG_ADDR, /* TTECP - NA */ - 0x08, /* NAC */ - 0x0e, /* FCC */ - INVALID_REG_ADDR, /* CYCT - NA */ - INVALID_REG_ADDR, /* AE - NA */ - 0x1c, /* SOC */ - 0x3c, /* DCAP */ - 0x18, /* AP */ + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x02, + [BQ27XXX_REG_INT_TEMP] = 0x1e, + [BQ27XXX_REG_VOLT] = 0x04, + [BQ27XXX_REG_AI] = 0x10, + [BQ27XXX_REG_FLAGS] = 0x06, + [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x08, + [BQ27XXX_REG_FCC] = 0x0e, + [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x1c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x18, }; static u8 *bq27xxx_regs[] = { -- cgit v1.2.3 From cecbf8d52e6c7f16d954091be9283b928199ed92 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 2 Jun 2016 19:18:53 +0200 Subject: power: axp20x_usb: Add support for usb power-supply on axp22x pmics The usb power-supply on the axp22x pmics is mostly identical to the one on the axp20x pmics. One significant difference is that it cannot measure / monitor the usb voltage / current. Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../bindings/power_supply/axp20x_usb_power.txt | 3 +- drivers/power/axp20x_usb_power.c | 92 ++++++++++++++++------ 2 files changed, 71 insertions(+), 24 deletions(-) (limited to 'drivers/power') diff --git a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt b/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt index 862f4a49dc49..f1d7beec45bf 100644 --- a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt +++ b/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt @@ -1,7 +1,8 @@ AXP20x USB power supply Required Properties: --compatible: "x-powers,axp202-usb-power-supply" +-compatible: One of: "x-powers,axp202-usb-power-supply" + "x-powers,axp221-usb-power-supply" This node is a subnode of the axp20x PMIC. diff --git a/drivers/power/axp20x_usb_power.c b/drivers/power/axp20x_usb_power.c index 421a90b83567..6af6feb7058d 100644 --- a/drivers/power/axp20x_usb_power.c +++ b/drivers/power/axp20x_usb_power.c @@ -42,6 +42,7 @@ #define AXP20X_VBUS_MON_VBUS_VALID BIT(3) struct axp20x_usb_power { + struct device_node *np; struct regmap *regmap; struct power_supply *supply; }; @@ -85,7 +86,12 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, switch (v & AXP20X_VBUS_CLIMIT_MASK) { case AXP20X_VBUC_CLIMIT_100mA: - val->intval = 100000; + if (of_device_is_compatible(power->np, + "x-powers,axp202-usb-power-supply")) { + val->intval = 100000; + } else { + val->intval = -1; /* No 100mA limit */ + } break; case AXP20X_VBUC_CLIMIT_500mA: val->intval = 500000; @@ -122,16 +128,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, break; } - ret = regmap_read(power->regmap, AXP20X_USB_OTG_STATUS, &v); - if (ret) - return ret; + val->intval = POWER_SUPPLY_HEALTH_GOOD; - if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) { - val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; - break; - } + if (of_device_is_compatible(power->np, + "x-powers,axp202-usb-power-supply")) { + ret = regmap_read(power->regmap, + AXP20X_USB_OTG_STATUS, &v); + if (ret) + return ret; - val->intval = POWER_SUPPLY_HEALTH_GOOD; + if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) + val->intval = + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + } break; case POWER_SUPPLY_PROP_PRESENT: val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); @@ -156,6 +165,14 @@ static enum power_supply_property axp20x_usb_power_properties[] = { POWER_SUPPLY_PROP_CURRENT_NOW, }; +static enum power_supply_property axp22x_usb_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_CURRENT_MAX, +}; + static const struct power_supply_desc axp20x_usb_power_desc = { .name = "axp20x-usb", .type = POWER_SUPPLY_TYPE_USB, @@ -164,13 +181,25 @@ static const struct power_supply_desc axp20x_usb_power_desc = { .get_property = axp20x_usb_power_get_property, }; +static const struct power_supply_desc axp22x_usb_power_desc = { + .name = "axp20x-usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = axp22x_usb_power_properties, + .num_properties = ARRAY_SIZE(axp22x_usb_power_properties), + .get_property = axp20x_usb_power_get_property, +}; + static int axp20x_usb_power_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct power_supply_config psy_cfg = {}; struct axp20x_usb_power *power; - static const char * const irq_names[] = { "VBUS_PLUGIN", - "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID" }; + static const char * const axp20x_irq_names[] = { "VBUS_PLUGIN", + "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID", NULL }; + static const char * const axp22x_irq_names[] = { + "VBUS_PLUGIN", "VBUS_REMOVAL", NULL }; + static const char * const *irq_names; + const struct power_supply_desc *usb_power_desc; int i, irq, ret; if (!of_device_is_available(pdev->dev.of_node)) @@ -185,31 +214,47 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (!power) return -ENOMEM; + power->np = pdev->dev.of_node; power->regmap = axp20x->regmap; - /* Enable vbus valid checking */ - ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, - AXP20X_VBUS_MON_VBUS_VALID, AXP20X_VBUS_MON_VBUS_VALID); - if (ret) - return ret; + if (of_device_is_compatible(power->np, + "x-powers,axp202-usb-power-supply")) { + /* Enable vbus valid checking */ + ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, + AXP20X_VBUS_MON_VBUS_VALID, + AXP20X_VBUS_MON_VBUS_VALID); + if (ret) + return ret; - /* Enable vbus voltage and current measurement */ - ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, + /* Enable vbus voltage and current measurement */ + ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT, AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT); - if (ret) - return ret; + if (ret) + return ret; + + usb_power_desc = &axp20x_usb_power_desc; + irq_names = axp20x_irq_names; + } else if (of_device_is_compatible(power->np, + "x-powers,axp221-usb-power-supply")) { + usb_power_desc = &axp22x_usb_power_desc; + irq_names = axp22x_irq_names; + } else { + dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", + axp20x->variant); + return -EINVAL; + } psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = power; - power->supply = devm_power_supply_register(&pdev->dev, - &axp20x_usb_power_desc, &psy_cfg); + power->supply = devm_power_supply_register(&pdev->dev, usb_power_desc, + &psy_cfg); if (IS_ERR(power->supply)) return PTR_ERR(power->supply); /* Request irqs after registering, as irqs may trigger immediately */ - for (i = 0; i < ARRAY_SIZE(irq_names); i++) { + for (i = 0; irq_names[i]; i++) { irq = platform_get_irq_byname(pdev, irq_names[i]); if (irq < 0) { dev_warn(&pdev->dev, "No IRQ for %s: %d\n", @@ -229,6 +274,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) static const struct of_device_id axp20x_usb_power_match[] = { { .compatible = "x-powers,axp202-usb-power-supply" }, + { .compatible = "x-powers,axp221-usb-power-supply" }, { } }; MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); -- cgit v1.2.3 From d04b674e188756c8e90a1cf422fe12ab1f147e4e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 19:28:54 +0100 Subject: power/reset: make syscon_poweroff() static The syscon_poweroff() function is not exported or declared for usage elsewhere, so make it static to avoid the folloiwing warning: drivers/power/reset/syscon-poweroff.c:33:6: warning: symbol 'syscon_poweroff' was not declared. Should it be static? Signed-off-by: Ben Dooks Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 5560b0dbc180..b68338399e5e 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -30,7 +30,7 @@ static struct regmap *map; static u32 offset; static u32 mask; -void syscon_poweroff(void) +static void syscon_poweroff(void) { /* Issue the poweroff */ regmap_write(map, offset, mask); -- cgit v1.2.3 From 2e05b518c89714d60000dfe0cd39490da68763e0 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 17 Jun 2016 17:02:35 -0500 Subject: power_supply: bq27xxx_battery: Group register mappings into one table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently for each device with a unique register map we have a named array that we then merge into a multidimensional array. Skip this middle step and apply the register arrays directly to the multi-array. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/bq27xxx_battery.c | 284 +++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 148 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c index 01737fab0048..b073338f63d5 100644 --- a/drivers/power/bq27xxx_battery.c +++ b/drivers/power/bq27xxx_battery.c @@ -82,6 +82,7 @@ * * These are indexes into a device's register mapping array. */ + enum bq27xxx_reg_index { BQ27XXX_REG_CTRL = 0, /* Control */ BQ27XXX_REG_TEMP, /* Temperature */ @@ -100,157 +101,144 @@ enum bq27xxx_reg_index { BQ27XXX_REG_SOC, /* State-of-Charge */ BQ27XXX_REG_DCAP, /* Design Capacity */ BQ27XXX_REG_AP, /* Average Power */ + BQ27XXX_REG_MAX, /* sentinel */ }; /* Register mappings */ -static u8 bq27000_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = 0x18, - [BQ27XXX_REG_TTES] = 0x1c, - [BQ27XXX_REG_TTECP] = 0x26, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = 0x22, - [BQ27XXX_REG_SOC] = 0x0b, - [BQ27XXX_REG_DCAP] = 0x76, - [BQ27XXX_REG_AP] = 0x24, -}; - -static u8 bq27010_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = 0x18, - [BQ27XXX_REG_TTES] = 0x1c, - [BQ27XXX_REG_TTECP] = 0x26, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x0b, - [BQ27XXX_REG_DCAP] = 0x76, - [BQ27XXX_REG_AP] = INVALID_REG_ADDR, -}; - -static u8 bq27500_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = 0x28, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = 0x1a, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = 0x3c, - [BQ27XXX_REG_AP] = INVALID_REG_ADDR, -}; - -static u8 bq27530_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = 0x32, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, - [BQ27XXX_REG_AP] = 0x24, -}; - -static u8 bq27541_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = 0x28, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = 0x3c, - [BQ27XXX_REG_AP] = 0x24, -}; - -static u8 bq27545_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x06, - [BQ27XXX_REG_INT_TEMP] = 0x28, - [BQ27XXX_REG_VOLT] = 0x08, - [BQ27XXX_REG_AI] = 0x14, - [BQ27XXX_REG_FLAGS] = 0x0a, - [BQ27XXX_REG_TTE] = 0x16, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x0c, - [BQ27XXX_REG_FCC] = 0x12, - [BQ27XXX_REG_CYCT] = 0x2a, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x2c, - [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, - [BQ27XXX_REG_AP] = 0x24, -}; - -static u8 bq27421_regs[] = { - [BQ27XXX_REG_CTRL] = 0x00, - [BQ27XXX_REG_TEMP] = 0x02, - [BQ27XXX_REG_INT_TEMP] = 0x1e, - [BQ27XXX_REG_VOLT] = 0x04, - [BQ27XXX_REG_AI] = 0x10, - [BQ27XXX_REG_FLAGS] = 0x06, - [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, - [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, - [BQ27XXX_REG_NAC] = 0x08, - [BQ27XXX_REG_FCC] = 0x0e, - [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, - [BQ27XXX_REG_AE] = INVALID_REG_ADDR, - [BQ27XXX_REG_SOC] = 0x1c, - [BQ27XXX_REG_DCAP] = 0x3c, - [BQ27XXX_REG_AP] = 0x18, -}; - -static u8 *bq27xxx_regs[] = { - [BQ27000] = bq27000_regs, - [BQ27010] = bq27010_regs, - [BQ27500] = bq27500_regs, - [BQ27530] = bq27530_regs, - [BQ27541] = bq27541_regs, - [BQ27545] = bq27545_regs, - [BQ27421] = bq27421_regs, +static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { + [BQ27000] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x0b, + [BQ27XXX_REG_DCAP] = 0x76, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27010] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x0b, + [BQ27XXX_REG_DCAP] = 0x76, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, + }, + [BQ27500] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1a, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, + }, + [BQ27530] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x32, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27541] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27545] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27421] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x02, + [BQ27XXX_REG_INT_TEMP] = 0x1e, + [BQ27XXX_REG_VOLT] = 0x04, + [BQ27XXX_REG_AI] = 0x10, + [BQ27XXX_REG_FLAGS] = 0x06, + [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x08, + [BQ27XXX_REG_FCC] = 0x0e, + [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x1c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x18, + }, }; static enum power_supply_property bq27000_battery_props[] = { -- cgit v1.2.3 From 0c3ae04b00f5664b98435b072c1694e62a823e5a Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:07 +1000 Subject: max8903: store pointer to pdata instead of copying it. Stores pointer to pdata because it easily allows pdata to reference either platform data or in the future device tree data. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 17876caf31e5..0a5b0e142788 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -29,7 +29,7 @@ #include struct max8903_data { - struct max8903_pdata pdata; + struct max8903_pdata *pdata; struct device *dev; struct power_supply *psy; struct power_supply_desc psy_desc; @@ -53,8 +53,8 @@ static int max8903_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; - if (data->pdata.chg) { - if (gpio_get_value(data->pdata.chg) == 0) + if (data->pdata->chg) { + if (gpio_get_value(data->pdata->chg) == 0) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (data->usb_in || data->ta_in) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; @@ -81,7 +81,7 @@ static int max8903_get_property(struct power_supply *psy, static irqreturn_t max8903_dcin(int irq, void *_data) { struct max8903_data *data = _data; - struct max8903_pdata *pdata = &data->pdata; + struct max8903_pdata *pdata = data->pdata; bool ta_in; enum power_supply_type old_type; @@ -122,7 +122,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data) static irqreturn_t max8903_usbin(int irq, void *_data) { struct max8903_data *data = _data; - struct max8903_pdata *pdata = &data->pdata; + struct max8903_pdata *pdata = data->pdata; bool usb_in; enum power_supply_type old_type; @@ -161,7 +161,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data) static irqreturn_t max8903_fault(int irq, void *_data) { struct max8903_data *data = _data; - struct max8903_pdata *pdata = &data->pdata; + struct max8903_pdata *pdata = data->pdata; bool fault; fault = gpio_get_value(pdata->flt) ? false : true; @@ -190,12 +190,18 @@ static int max8903_probe(struct platform_device *pdev) int ta_in = 0; int usb_in = 0; + if (pdata == NULL) { + dev_err(dev, "No platform data.\n"); + return -EINVAL; + } + data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); if (data == NULL) { dev_err(dev, "Cannot allocate memory.\n"); return -ENOMEM; } - memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata)); + + data->pdata = pdev->dev.platform_data; data->dev = dev; platform_set_drvdata(pdev, data); -- cgit v1.2.3 From cbf9077e586b9c0db1a1ce5690552ae268c15848 Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:08 +1000 Subject: max8903: cleans up confusing relationship between dc_valid, dok and dcm. The max8903_charger.h file indicated that dcm and dok were not optional when dc_valid is set. It makes sense to have dok as a compulsory pin when dc_valid is given. However dcm can be optionally wired to a fixed level especially when the circuit is configured for dc power exclusively. The previous implementation already allowed for this somewhat, however no error was given if dok wasn't given whilst dc_valid was. The new implementation enforces dok presence when dc_valid is given. Whilst allowing dcm to be optional. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 22 +++++++++------------- include/linux/power/max8903_charger.h | 6 +++--- 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 0a5b0e142788..6ec705f7a9d9 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -211,27 +211,23 @@ static int max8903_probe(struct platform_device *pdev) } if (pdata->dc_valid) { - if (pdata->dok && gpio_is_valid(pdata->dok) && - pdata->dcm && gpio_is_valid(pdata->dcm)) { + if (pdata->dok && gpio_is_valid(pdata->dok)) { gpio = pdata->dok; /* PULL_UPed Interrupt */ ta_in = gpio_get_value(gpio) ? 0 : 1; + } else { + dev_err(dev, "When DC is wired, DOK should be wired as well.\n"); + return -EINVAL; + } + } + if (pdata->dcm) { + if (gpio_is_valid(pdata->dcm)) { gpio = pdata->dcm; /* Output */ gpio_set_value(gpio, ta_in); } else { - dev_err(dev, "When DC is wired, DOK and DCM should" - " be wired as well.\n"); + dev_err(dev, "Invalid pin: dcm.\n"); return -EINVAL; } - } else { - if (pdata->dcm) { - if (gpio_is_valid(pdata->dcm)) - gpio_set_value(pdata->dcm, 0); - else { - dev_err(dev, "Invalid pin: dcm.\n"); - return -EINVAL; - } - } } if (pdata->usb_valid) { diff --git a/include/linux/power/max8903_charger.h b/include/linux/power/max8903_charger.h index 24f51db8a83f..89d3f1cb3433 100644 --- a/include/linux/power/max8903_charger.h +++ b/include/linux/power/max8903_charger.h @@ -26,8 +26,8 @@ struct max8903_pdata { /* * GPIOs - * cen, chg, flt, and usus are optional. - * dok, dcm, and uok are not optional depending on the status of + * cen, chg, flt, dcm and usus are optional. + * dok and uok are not optional depending on the status of * dc_valid and usb_valid. */ int cen; /* Charger Enable input */ @@ -41,7 +41,7 @@ struct max8903_pdata { /* * DC(Adapter/TA) is wired * When dc_valid is true, - * dok and dcm should be valid. + * dok should be valid. * * At least one of dc_valid or usb_valid should be true. */ -- cgit v1.2.3 From 88a469bbb2012448db266f3783448c673be7208a Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:09 +1000 Subject: max8903: adds requesting of gpios. This change ensures all gpios are available for the driver to use and also splits off gpio setup into its own function for readability. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 136 ++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 34 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 6ec705f7a9d9..3f35593443b3 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -179,39 +179,27 @@ static irqreturn_t max8903_fault(int irq, void *_data) return IRQ_HANDLED; } -static int max8903_probe(struct platform_device *pdev) +static int max8903_setup_gpios(struct platform_device *pdev) { - struct max8903_data *data; + struct max8903_data *data = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; struct max8903_pdata *pdata = pdev->dev.platform_data; - struct power_supply_config psy_cfg = {}; int ret = 0; int gpio; int ta_in = 0; int usb_in = 0; - if (pdata == NULL) { - dev_err(dev, "No platform data.\n"); - return -EINVAL; - } - - data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); - if (data == NULL) { - dev_err(dev, "Cannot allocate memory.\n"); - return -ENOMEM; - } - - data->pdata = pdev->dev.platform_data; - data->dev = dev; - platform_set_drvdata(pdev, data); - - if (pdata->dc_valid == false && pdata->usb_valid == false) { - dev_err(dev, "No valid power sources.\n"); - return -EINVAL; - } - if (pdata->dc_valid) { if (pdata->dok && gpio_is_valid(pdata->dok)) { + ret = devm_gpio_request(dev, pdata->dok, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for dok: %d err %d\n", + pdata->dok, ret); + return ret; + } + gpio = pdata->dok; /* PULL_UPed Interrupt */ ta_in = gpio_get_value(gpio) ? 0 : 1; } else { @@ -222,6 +210,15 @@ static int max8903_probe(struct platform_device *pdev) if (pdata->dcm) { if (gpio_is_valid(pdata->dcm)) { + ret = devm_gpio_request(dev, pdata->dcm, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for dcm: %d err %d\n", + pdata->dcm, ret); + return ret; + } + gpio = pdata->dcm; /* Output */ gpio_set_value(gpio, ta_in); } else { @@ -232,6 +229,15 @@ static int max8903_probe(struct platform_device *pdev) if (pdata->usb_valid) { if (pdata->uok && gpio_is_valid(pdata->uok)) { + ret = devm_gpio_request(dev, pdata->uok, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for uok: %d err %d\n", + pdata->uok, ret); + return ret; + } + gpio = pdata->uok; usb_in = gpio_get_value(gpio) ? 0 : 1; } else { @@ -243,6 +249,15 @@ static int max8903_probe(struct platform_device *pdev) if (pdata->cen) { if (gpio_is_valid(pdata->cen)) { + ret = devm_gpio_request(dev, pdata->cen, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for cen: %d err %d\n", + pdata->cen, ret); + return ret; + } + gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); } else { dev_err(dev, "Invalid pin: cen.\n"); @@ -251,23 +266,41 @@ static int max8903_probe(struct platform_device *pdev) } if (pdata->chg) { - if (!gpio_is_valid(pdata->chg)) { - dev_err(dev, "Invalid pin: chg.\n"); - return -EINVAL; + if (gpio_is_valid(pdata->chg)) { + ret = devm_gpio_request(dev, pdata->chg, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for chg: %d err %d\n", + pdata->chg, ret); + return ret; + } } } if (pdata->flt) { - if (!gpio_is_valid(pdata->flt)) { - dev_err(dev, "Invalid pin: flt.\n"); - return -EINVAL; + if (gpio_is_valid(pdata->flt)) { + ret = devm_gpio_request(dev, pdata->flt, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for flt: %d err %d\n", + pdata->flt, ret); + return ret; + } } } if (pdata->usus) { - if (!gpio_is_valid(pdata->usus)) { - dev_err(dev, "Invalid pin: usus.\n"); - return -EINVAL; + if (gpio_is_valid(pdata->usus)) { + ret = devm_gpio_request(dev, pdata->usus, + data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for usus: %d err %d\n", + pdata->usus, ret); + return ret; + } } } @@ -275,9 +308,44 @@ static int max8903_probe(struct platform_device *pdev) data->ta_in = ta_in; data->usb_in = usb_in; + return 0; +} + +static int max8903_probe(struct platform_device *pdev) +{ + struct max8903_data *data; + struct device *dev = &pdev->dev; + struct max8903_pdata *pdata = pdev->dev.platform_data; + struct power_supply_config psy_cfg = {}; + int ret = 0; + + if (pdata == NULL) { + dev_err(dev, "No platform data.\n"); + return -EINVAL; + } + + data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); + if (data == NULL) { + dev_err(dev, "Cannot allocate memory.\n"); + return -ENOMEM; + } + + data->pdata = pdev->dev.platform_data; + data->dev = dev; + platform_set_drvdata(pdev, data); + + if (pdata->dc_valid == false && pdata->usb_valid == false) { + dev_err(dev, "No valid power sources.\n"); + return -EINVAL; + } + + ret = max8903_setup_gpios(pdev); + if (ret) + return ret; + data->psy_desc.name = "max8903_charger"; - data->psy_desc.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS : - ((usb_in) ? POWER_SUPPLY_TYPE_USB : + data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS : + ((data->usb_in) ? POWER_SUPPLY_TYPE_USB : POWER_SUPPLY_TYPE_BATTERY); data->psy_desc.get_property = max8903_get_property; data->psy_desc.properties = max8903_charger_props; -- cgit v1.2.3 From 3525e5c5b3dea03ff999c53be6392819165df820 Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:10 +1000 Subject: max8903: removes non zero validity checks on gpios. Prior to this commit a zero gpio was treated as invalid. Whereas gpio_is_valid() will treat a zero gpio as valid. This commit removes the confusion and explicitly uses gpio_is_valid() throughout. Which in turn results in several of the error messages becoming redundant and thus removed. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 115 ++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 68 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 3f35593443b3..643a87aac60f 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -53,7 +53,7 @@ static int max8903_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; - if (data->pdata->chg) { + if (gpio_is_valid(data->pdata->chg)) { if (gpio_get_value(data->pdata->chg) == 0) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (data->usb_in || data->ta_in) @@ -93,11 +93,11 @@ static irqreturn_t max8903_dcin(int irq, void *_data) data->ta_in = ta_in; /* Set Current-Limit-Mode 1:DC 0:USB */ - if (pdata->dcm) + if (gpio_is_valid(pdata->dcm)) gpio_set_value(pdata->dcm, ta_in ? 1 : 0); /* Charger Enable / Disable (cen is negated) */ - if (pdata->cen) + if (gpio_is_valid(pdata->cen)) gpio_set_value(pdata->cen, ta_in ? 0 : (data->usb_in ? 0 : 1)); @@ -136,7 +136,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data) /* Do not touch Current-Limit-Mode */ /* Charger Enable / Disable (cen is negated) */ - if (pdata->cen) + if (gpio_is_valid(pdata->cen)) gpio_set_value(pdata->cen, usb_in ? 0 : (data->ta_in ? 0 : 1)); @@ -190,7 +190,7 @@ static int max8903_setup_gpios(struct platform_device *pdev) int usb_in = 0; if (pdata->dc_valid) { - if (pdata->dok && gpio_is_valid(pdata->dok)) { + if (gpio_is_valid(pdata->dok)) { ret = devm_gpio_request(dev, pdata->dok, data->psy_desc.name); if (ret) { @@ -208,27 +208,21 @@ static int max8903_setup_gpios(struct platform_device *pdev) } } - if (pdata->dcm) { - if (gpio_is_valid(pdata->dcm)) { - ret = devm_gpio_request(dev, pdata->dcm, - data->psy_desc.name); - if (ret) { - dev_err(dev, - "Failed GPIO request for dcm: %d err %d\n", - pdata->dcm, ret); - return ret; - } - - gpio = pdata->dcm; /* Output */ - gpio_set_value(gpio, ta_in); - } else { - dev_err(dev, "Invalid pin: dcm.\n"); - return -EINVAL; + if (gpio_is_valid(pdata->dcm)) { + ret = devm_gpio_request(dev, pdata->dcm, data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for dcm: %d err %d\n", + pdata->dcm, ret); + return ret; } + + gpio = pdata->dcm; /* Output */ + gpio_set_value(gpio, ta_in); } if (pdata->usb_valid) { - if (pdata->uok && gpio_is_valid(pdata->uok)) { + if (gpio_is_valid(pdata->uok)) { ret = devm_gpio_request(dev, pdata->uok, data->psy_desc.name); if (ret) { @@ -247,60 +241,45 @@ static int max8903_setup_gpios(struct platform_device *pdev) } } - if (pdata->cen) { - if (gpio_is_valid(pdata->cen)) { - ret = devm_gpio_request(dev, pdata->cen, - data->psy_desc.name); - if (ret) { - dev_err(dev, - "Failed GPIO request for cen: %d err %d\n", - pdata->cen, ret); - return ret; - } - - gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); - } else { - dev_err(dev, "Invalid pin: cen.\n"); - return -EINVAL; + if (gpio_is_valid(pdata->cen)) { + ret = devm_gpio_request(dev, pdata->cen, data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for cen: %d err %d\n", + pdata->cen, ret); + return ret; } + + gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); } - if (pdata->chg) { - if (gpio_is_valid(pdata->chg)) { - ret = devm_gpio_request(dev, pdata->chg, - data->psy_desc.name); - if (ret) { - dev_err(dev, - "Failed GPIO request for chg: %d err %d\n", - pdata->chg, ret); - return ret; - } + if (gpio_is_valid(pdata->chg)) { + ret = devm_gpio_request(dev, pdata->chg, data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for chg: %d err %d\n", + pdata->chg, ret); + return ret; } } - if (pdata->flt) { - if (gpio_is_valid(pdata->flt)) { - ret = devm_gpio_request(dev, pdata->flt, - data->psy_desc.name); - if (ret) { - dev_err(dev, - "Failed GPIO request for flt: %d err %d\n", - pdata->flt, ret); - return ret; - } + if (gpio_is_valid(pdata->flt)) { + ret = devm_gpio_request(dev, pdata->flt, data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for flt: %d err %d\n", + pdata->flt, ret); + return ret; } } - if (pdata->usus) { - if (gpio_is_valid(pdata->usus)) { - ret = devm_gpio_request(dev, pdata->usus, - data->psy_desc.name); - if (ret) { - dev_err(dev, - "Failed GPIO request for usus: %d err %d\n", - pdata->usus, ret); - return ret; - } + if (gpio_is_valid(pdata->usus)) { + ret = devm_gpio_request(dev, pdata->usus, data->psy_desc.name); + if (ret) { + dev_err(dev, + "Failed GPIO request for usus: %d err %d\n", + pdata->usus, ret); + return ret; } } @@ -385,7 +364,7 @@ static int max8903_probe(struct platform_device *pdev) } } - if (pdata->flt) { + if (gpio_is_valid(pdata->flt)) { ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt), NULL, max8903_fault, IRQF_TRIGGER_FALLING | -- cgit v1.2.3 From e6518a43253944108832764656283a818949c75f Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:11 +1000 Subject: max8903: remove unnecessary 'out of memory' error message. Remove the 'out of memory' error message as it is printed by the core. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 643a87aac60f..9453bbff6075 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -304,10 +304,8 @@ static int max8903_probe(struct platform_device *pdev) } data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); - if (data == NULL) { - dev_err(dev, "Cannot allocate memory.\n"); + if (!data) return -ENOMEM; - } data->pdata = pdev->dev.platform_data; data->dev = dev; -- cgit v1.2.3 From c5ed3307940bc4584ce99236f033d60435d83036 Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:12 +1000 Subject: max8903: adds support for initiation via device tree Adds support for device tree to setup a max8903 battery charger. DC and USB validity are determined by looking the presence of the dok and uok gpios. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 78 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 9453bbff6075..fdc73d686153 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -75,6 +78,7 @@ static int max8903_get_property(struct power_supply *psy, default: return -EINVAL; } + return 0; } @@ -179,6 +183,56 @@ static irqreturn_t max8903_fault(int irq, void *_data) return IRQ_HANDLED; } +static struct max8903_pdata *max8903_parse_dt_data(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct max8903_pdata *pdata = NULL; + + if (!np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->dc_valid = false; + pdata->usb_valid = false; + + pdata->cen = of_get_named_gpio(np, "cen-gpios", 0); + if (!gpio_is_valid(pdata->cen)) + pdata->cen = -EINVAL; + + pdata->chg = of_get_named_gpio(np, "chg-gpios", 0); + if (!gpio_is_valid(pdata->chg)) + pdata->chg = -EINVAL; + + pdata->flt = of_get_named_gpio(np, "flt-gpios", 0); + if (!gpio_is_valid(pdata->flt)) + pdata->flt = -EINVAL; + + pdata->usus = of_get_named_gpio(np, "usus-gpios", 0); + if (!gpio_is_valid(pdata->usus)) + pdata->usus = -EINVAL; + + pdata->dcm = of_get_named_gpio(np, "dcm-gpios", 0); + if (!gpio_is_valid(pdata->dcm)) + pdata->dcm = -EINVAL; + + pdata->dok = of_get_named_gpio(np, "dok-gpios", 0); + if (!gpio_is_valid(pdata->dok)) + pdata->dok = -EINVAL; + else + pdata->dc_valid = true; + + pdata->uok = of_get_named_gpio(np, "uok-gpios", 0); + if (!gpio_is_valid(pdata->uok)) + pdata->uok = -EINVAL; + else + pdata->usb_valid = true; + + return pdata; +} + static int max8903_setup_gpios(struct platform_device *pdev) { struct max8903_data *data = platform_get_drvdata(pdev); @@ -298,16 +352,20 @@ static int max8903_probe(struct platform_device *pdev) struct power_supply_config psy_cfg = {}; int ret = 0; - if (pdata == NULL) { - dev_err(dev, "No platform data.\n"); - return -EINVAL; - } - data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); if (!data) return -ENOMEM; - data->pdata = pdev->dev.platform_data; + if (IS_ENABLED(CONFIG_OF) && !pdata && dev->of_node) + pdata = max8903_parse_dt_data(dev); + + if (!pdata) { + dev_err(dev, "No platform data.\n"); + return -EINVAL; + } + + pdev->dev.platform_data = pdata; + data->pdata = pdata; data->dev = dev; platform_set_drvdata(pdev, data); @@ -328,6 +386,7 @@ static int max8903_probe(struct platform_device *pdev) data->psy_desc.properties = max8903_charger_props; data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); + psy_cfg.of_node = dev->of_node; psy_cfg.drv_data = data; data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); @@ -378,10 +437,17 @@ static int max8903_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id max8903_match_ids[] = { + { .compatible = "maxim,max8903", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max8903_match_ids); + static struct platform_driver max8903_driver = { .probe = max8903_probe, .driver = { .name = "max8903-charger", + .of_match_table = max8903_match_ids }, }; -- cgit v1.2.3 From eee1d077f0d74bcd411c18148a31a5d3aab42284 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:54:37 -0700 Subject: power: qcom_smbb: Make an extcon for usb cable detection On these PMICs the usb cable connection/disconnection is indicated by the usb-valid interrupt being high or low respectively. Let's make an extcon for that, so we can notify usb drivers of the cable state. Cc: Bjorn Andersson Cc: Chanwoo Choi Signed-off-by: Stephen Boyd Reviewed-by: Chanwoo Choi Signed-off-by: Sebastian Reichel --- drivers/power/Kconfig | 1 + drivers/power/qcom_smbb.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'drivers/power') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 421770ddafa3..6bff735c632d 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -393,6 +393,7 @@ config CHARGER_QCOM_SMBB tristate "Qualcomm Switch-Mode Battery Charger and Boost" depends on MFD_SPMI_PMIC || COMPILE_TEST depends on OF + depends on EXTCON help Say Y to include support for the Switch-Mode Battery Charger and Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger diff --git a/drivers/power/qcom_smbb.c b/drivers/power/qcom_smbb.c index 5eb1e9e543e2..b5896ba2a602 100644 --- a/drivers/power/qcom_smbb.c +++ b/drivers/power/qcom_smbb.c @@ -34,6 +34,7 @@ #include #include #include +#include #define SMBB_CHG_VMAX 0x040 #define SMBB_CHG_VSAFE 0x041 @@ -111,6 +112,7 @@ struct smbb_charger { unsigned int revision; unsigned int addr; struct device *dev; + struct extcon_dev *edev; bool dc_disabled; bool jeita_ext_temp; @@ -125,6 +127,11 @@ struct smbb_charger { struct regmap *regmap; }; +static const unsigned int smbb_usb_extcon_cable[] = { + EXTCON_USB, + EXTCON_NONE, +}; + static int smbb_vbat_weak_fn(unsigned int index) { return 2100000 + index * 100000; @@ -371,6 +378,8 @@ static irqreturn_t smbb_usb_valid_handler(int irq, void *_data) struct smbb_charger *chg = _data; smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); + extcon_set_cable_state_(chg->edev, EXTCON_USB, + chg->status & STATUS_USBIN_VALID); power_supply_changed(chg->usb_psy); return IRQ_HANDLED; @@ -849,6 +858,18 @@ static int smbb_charger_probe(struct platform_device *pdev) return PTR_ERR(chg->usb_psy); } + chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable); + if (IS_ERR(chg->edev)) { + dev_err(&pdev->dev, "failed to allocate extcon device\n"); + return -ENOMEM; + } + + rc = devm_extcon_dev_register(&pdev->dev, chg->edev); + if (rc < 0) { + dev_err(&pdev->dev, "failed to register extcon device\n"); + return rc; + } + if (!chg->dc_disabled) { dc_cfg.drv_data = chg; dc_cfg.supplied_to = smbb_bif; -- cgit v1.2.3 From e380538529e83c5d3fd27e8cbfcc1f9799cb6bbb Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 22 Jun 2016 11:45:52 -0400 Subject: power_supply: fix return value of get_property power_supply_get_property() should ideally return -EAGAIN if it is called while the power_supply is being registered. There was no way previously to determine if use_cnt == 0 meant that the power_supply wasn't fully registered yet, or if it had already been unregistered. Add a new boolean to the power_supply struct to simply show if registration is completed. Lastly, modify the check in power_supply_show_property() to also ignore -EAGAIN when so it doesn't complain about not returning the property. Signed-off-by: Rhyland Klein Signed-off-by: Sebastian Reichel --- drivers/power/power_supply_core.c | 6 +++++- drivers/power/power_supply_sysfs.c | 2 +- include/linux/power_supply.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 456987c88baa..c2ef0c0dfa9d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -491,8 +491,11 @@ int power_supply_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - if (atomic_read(&psy->use_cnt) <= 0) + if (atomic_read(&psy->use_cnt) <= 0) { + if (!psy->initialized) + return -EAGAIN; return -ENODEV; + } return psy->desc->get_property(psy, psp, val); } @@ -780,6 +783,7 @@ __power_supply_register(struct device *parent, * after calling power_supply_register()). */ atomic_inc(&psy->use_cnt); + psy->initialized = true; queue_delayed_work(system_power_efficient_wq, &psy->deferred_register_work, diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 80fed98832f9..bcde8d13476a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -83,7 +83,7 @@ static ssize_t power_supply_show_property(struct device *dev, if (ret == -ENODATA) dev_dbg(dev, "driver has no data for `%s' property\n", attr->attr.name); - else if (ret != -ENODEV) + else if (ret != -ENODEV && ret != -EAGAIN) dev_err(dev, "driver failed to report `%s' property: %zd\n", attr->attr.name, ret); return ret; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 751061790626..3965503315ef 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -248,6 +248,7 @@ struct power_supply { struct delayed_work deferred_register_work; spinlock_t changed_lock; bool changed; + bool initialized; atomic_t use_cnt; #ifdef CONFIG_THERMAL struct thermal_zone_device *tzd; -- cgit v1.2.3 From 4fcd504edbf7c793325511c2df8dcd083958e28a Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Wed, 6 Jul 2016 21:27:26 +0800 Subject: power: reset: add reboot mode driver This driver parses the reboot commands like "reboot bootloader" and "reboot recovery" to get a boot mode described in the device tree , then call the write interfae to store the boot mode in some place like special register or sram, which can be read by the bootloader after system reboot, then the bootloader can take different action according to the mode stored. This is commonly used on Android based devices, in order to reboot the device into fastboot or recovery mode. Reviewed-by: Matthias Brugger Reviewed-by: Moritz Fischer Tested-by: John Stultz Acked-by: John Stultz Signed-off-by: Andy Yan Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 14 ++++ drivers/power/reset/Makefile | 2 + drivers/power/reset/reboot-mode.c | 140 +++++++++++++++++++++++++++++++ drivers/power/reset/reboot-mode.h | 14 ++++ drivers/power/reset/syscon-reboot-mode.c | 99 ++++++++++++++++++++++ 5 files changed, 269 insertions(+) create mode 100644 drivers/power/reset/reboot-mode.c create mode 100644 drivers/power/reset/reboot-mode.h create mode 100644 drivers/power/reset/syscon-reboot-mode.c (limited to 'drivers/power') diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 0cc8fc97e14d..7053abced0bc 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -184,5 +184,19 @@ config POWER_RESET_ZX help Reboot support for ZTE SoCs. +config REBOOT_MODE + tristate + +config SYSCON_REBOOT_MODE + tristate "Generic SYSCON regmap reboot mode driver" + depends on OF + select REBOOT_MODE + select MFD_SYSCON + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in SYSCON mapped + register, then the bootloader can read it to take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index ab7aa8614d1f..d6b2560d5c4a 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -21,3 +21,5 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o +obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o +obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c new file mode 100644 index 000000000000..2dfbbce0f817 --- /dev/null +++ b/drivers/power/reset/reboot-mode.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include "reboot-mode.h" + +#define PREFIX "mode-" + +struct mode_info { + const char *mode; + u32 magic; + struct list_head list; +}; + +static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, + const char *cmd) +{ + const char *normal = "normal"; + int magic = 0; + struct mode_info *info; + + if (!cmd) + cmd = normal; + + list_for_each_entry(info, &reboot->head, list) { + if (!strcmp(info->mode, cmd)) { + magic = info->magic; + break; + } + } + + return magic; +} + +static int reboot_mode_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct reboot_mode_driver *reboot; + unsigned int magic; + + reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); + magic = get_reboot_mode_magic(reboot, cmd); + if (magic) + reboot->write(reboot, magic); + + return NOTIFY_DONE; +} + +/** + * reboot_mode_register - register a reboot mode driver + * @reboot: reboot mode driver + * + * Returns: 0 on success or a negative error code on failure. + */ +int reboot_mode_register(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + struct property *prop; + struct device_node *np = reboot->dev->of_node; + size_t len = strlen(PREFIX); + int ret; + + INIT_LIST_HEAD(&reboot->head); + + for_each_property_of_node(np, prop) { + if (strncmp(prop->name, PREFIX, len)) + continue; + + info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto error; + } + + if (of_property_read_u32(np, prop->name, &info->magic)) { + dev_err(reboot->dev, "reboot mode %s without magic number\n", + info->mode); + devm_kfree(reboot->dev, info); + continue; + } + + info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); + if (!info->mode) { + ret = -ENOMEM; + goto error; + } else if (info->mode[0] == '\0') { + kfree_const(info->mode); + ret = -EINVAL; + dev_err(reboot->dev, "invalid mode name(%s): too short!\n", + prop->name); + goto error; + } + + list_add_tail(&info->list, &reboot->head); + } + + reboot->reboot_notifier.notifier_call = reboot_mode_notify; + register_reboot_notifier(&reboot->reboot_notifier); + + return 0; + +error: + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + + return ret; +} +EXPORT_SYMBOL_GPL(reboot_mode_register); + +/** + * reboot_mode_unregister - unregister a reboot mode driver + * @reboot: reboot mode driver + */ +int reboot_mode_unregister(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + + unregister_reboot_notifier(&reboot->reboot_notifier); + + list_for_each_entry(info, &reboot->head, list) + kfree_const(info->mode); + + return 0; +} +EXPORT_SYMBOL_GPL(reboot_mode_unregister); + +MODULE_AUTHOR("Andy Yan +#include +#include +#include +#include +#include +#include +#include +#include "reboot-mode.h" + +struct syscon_reboot_mode { + struct regmap *map; + struct reboot_mode_driver reboot; + u32 offset; + u32 mask; +}; + +static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + struct syscon_reboot_mode *syscon_rbm; + int ret; + + syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot); + + ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset, + syscon_rbm->mask, magic); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int syscon_reboot_mode_probe(struct platform_device *pdev) +{ + int ret; + struct syscon_reboot_mode *syscon_rbm; + + syscon_rbm = devm_kzalloc(&pdev->dev, sizeof(*syscon_rbm), GFP_KERNEL); + if (!syscon_rbm) + return -ENOMEM; + + syscon_rbm->reboot.dev = &pdev->dev; + syscon_rbm->reboot.write = syscon_reboot_mode_write; + syscon_rbm->mask = 0xffffffff; + + dev_set_drvdata(&pdev->dev, syscon_rbm); + + syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(syscon_rbm->map)) + return PTR_ERR(syscon_rbm->map); + + if (of_property_read_u32(pdev->dev.of_node, "offset", + &syscon_rbm->offset)) + return -EINVAL; + + of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask); + + ret = reboot_mode_register(&syscon_rbm->reboot); + if (ret) + dev_err(&pdev->dev, "can't register reboot mode\n"); + + return ret; +} + +static int syscon_reboot_mode_remove(struct platform_device *pdev) +{ + struct syscon_reboot_mode *syscon_rbm = dev_get_drvdata(&pdev->dev); + + return reboot_mode_unregister(&syscon_rbm->reboot); +} + +static const struct of_device_id syscon_reboot_mode_of_match[] = { + { .compatible = "syscon-reboot-mode" }, + {} +}; + +static struct platform_driver syscon_reboot_mode_driver = { + .probe = syscon_reboot_mode_probe, + .remove = syscon_reboot_mode_remove, + .driver = { + .name = "syscon-reboot-mode", + .of_match_table = syscon_reboot_mode_of_match, + }, +}; +module_platform_driver(syscon_reboot_mode_driver); + +MODULE_AUTHOR("Andy Yan