Commit f7816ad0 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull power supply and reset updates from Sebastian Reichel:
 - introduce reboot mode driver
 - add DT support to max8903
 - add power supply support for axp221
 - misc fixes

* tag 'for-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply:
  power: reset: add reboot mode driver
  dt-bindings: power: reset: add document for reboot-mode driver
  power_supply: fix return value of get_property
  power: qcom_smbb: Make an extcon for usb cable detection
  max8903: adds support for initiation via device tree
  max8903: adds documentation for device tree bindings.
  max8903: remove unnecessary 'out of memory' error message.
  max8903: removes non zero validity checks on gpios.
  max8903: adds requesting of gpios.
  max8903: cleans up confusing relationship between dc_valid, dok and dcm.
  max8903: store pointer to pdata instead of copying it.
  power_supply: bq27xxx_battery: Group register mappings into one table
  docs: Move brcm,bcm21664-resetmgr.txt
  power/reset: make syscon_poweroff() static
  power: axp20x_usb: Add support for usb power-supply on axp22x pmics
  power_supply: bq27xxx_battery: Index register numbers by enum
  power_supply: bq27xxx_battery: Fix copy/paste error in header comment
  MAINTAINERS: Add file patterns for power supply device tree bindings
  power: reset: keystone: Enable COMPILE_TEST
parents 6097d55e 4fcd504e
Maxim Semiconductor MAX8903 Battery Charger bindings
Required properties:
- compatible: "maxim,max8903" for MAX8903 Battery Charger
- dok-gpios: Valid DC power has been detected (active low, input), optional if uok-gpios is provided
- uok-gpios: Valid USB power has been detected (active low, input), optional if dok-gpios is provided
Optional properties:
- cen-gpios: Charge enable pin (active low, output)
- chg-gpios: Charger status pin (active low, input)
- flt-gpios: Fault pin (active low, output)
- dcm-gpios: Current limit mode setting (DC=1 or USB=0, output)
- usus-gpios: USB suspend pin (active high, output)
Example:
max8903-charger {
compatible = "maxim,max8903";
dok-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
flt-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
chg-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
cen-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
status = "okay";
};
Generic reboot mode core map driver
This driver get reboot mode arguments and call the write
interface to store the magic value in special register
or ram. Then the bootloader can read it and take different
action according to the argument stored.
All mode properties are vendor specific, it is a indication to tell
the bootloader what to do when the system reboots, and should be named
as mode-xxx = <magic> (xxx is mode name, magic should be a none-zero value).
For example modes common on Android platform:
- mode-normal: Normal reboot mode, system reboot with command "reboot".
- mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image.
- mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device.
- mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform,
usually used in development.
Example:
reboot-mode {
mode-normal = <BOOT_NORMAL>;
mode-recovery = <BOOT_RECOVERY>;
mode-bootloader = <BOOT_FASTBOOT>;
mode-loader = <BOOT_BL_DOWNLOAD>;
}
SYSCON reboot mode driver
This driver gets reboot mode magic value form reboot-mode driver
and stores it in a SYSCON mapped register. Then the bootloader
can read it and take different action according to the magic
value stored.
This DT node should be represented as a sub-node of a "syscon", "simple-mfd"
node.
Required properties:
- compatible: should be "syscon-reboot-mode"
- offset: offset in the register map for the storage register (in bytes)
Optional property:
- mask: bits mask of the bits in the register to store the reboot mode magic value,
default set to 0xffffffff if missing.
The rest of the properties should follow the generic reboot-mode description
found in reboot-mode.txt
Example:
pmu: pmu@20004000 {
compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
reg = <0x20004000 0x100>;
reboot-mode {
compatible = "syscon-reboot-mode";
offset = <0x40>;
mode-normal = <BOOT_NORMAL>;
mode-recovery = <BOOT_RECOVERY>;
mode-bootloader = <BOOT_FASTBOOT>;
mode-loader = <BOOT_BL_DOWNLOAD>;
};
};
AXP20x USB power supply AXP20x USB power supply
Required Properties: 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. This node is a subnode of the axp20x PMIC.
......
...@@ -9169,6 +9169,8 @@ M: David Woodhouse <dwmw2@infradead.org> ...@@ -9169,6 +9169,8 @@ M: David Woodhouse <dwmw2@infradead.org>
L: linux-pm@vger.kernel.org L: linux-pm@vger.kernel.org
T: git git://git.infradead.org/battery-2.6.git T: git git://git.infradead.org/battery-2.6.git
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/power/
F: Documentation/devicetree/bindings/power_supply/
F: include/linux/power_supply.h F: include/linux/power_supply.h
F: drivers/power/ F: drivers/power/
X: drivers/power/avs/ X: drivers/power/avs/
......
...@@ -394,6 +394,7 @@ config CHARGER_QCOM_SMBB ...@@ -394,6 +394,7 @@ config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost" tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST depends on MFD_SPMI_PMIC || COMPILE_TEST
depends on OF depends on OF
depends on EXTCON
help help
Say Y to include support for the Switch-Mode Battery Charger and Say Y to include support for the Switch-Mode Battery Charger and
Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define AXP20X_VBUS_MON_VBUS_VALID BIT(3) #define AXP20X_VBUS_MON_VBUS_VALID BIT(3)
struct axp20x_usb_power { struct axp20x_usb_power {
struct device_node *np;
struct regmap *regmap; struct regmap *regmap;
struct power_supply *supply; struct power_supply *supply;
}; };
...@@ -85,7 +86,12 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, ...@@ -85,7 +86,12 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
switch (v & AXP20X_VBUS_CLIMIT_MASK) { switch (v & AXP20X_VBUS_CLIMIT_MASK) {
case AXP20X_VBUC_CLIMIT_100mA: 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; break;
case AXP20X_VBUC_CLIMIT_500mA: case AXP20X_VBUC_CLIMIT_500mA:
val->intval = 500000; val->intval = 500000;
...@@ -122,16 +128,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, ...@@ -122,16 +128,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
break; break;
} }
ret = regmap_read(power->regmap, AXP20X_USB_OTG_STATUS, &v); val->intval = POWER_SUPPLY_HEALTH_GOOD;
if (ret)
return ret;
if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) { if (of_device_is_compatible(power->np,
val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; "x-powers,axp202-usb-power-supply")) {
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; break;
case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_PRESENT:
val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT);
...@@ -156,6 +165,14 @@ static enum power_supply_property axp20x_usb_power_properties[] = { ...@@ -156,6 +165,14 @@ static enum power_supply_property axp20x_usb_power_properties[] = {
POWER_SUPPLY_PROP_CURRENT_NOW, 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 = { static const struct power_supply_desc axp20x_usb_power_desc = {
.name = "axp20x-usb", .name = "axp20x-usb",
.type = POWER_SUPPLY_TYPE_USB, .type = POWER_SUPPLY_TYPE_USB,
...@@ -164,13 +181,25 @@ static const struct power_supply_desc axp20x_usb_power_desc = { ...@@ -164,13 +181,25 @@ static const struct power_supply_desc axp20x_usb_power_desc = {
.get_property = axp20x_usb_power_get_property, .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) static int axp20x_usb_power_probe(struct platform_device *pdev)
{ {
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
struct power_supply_config psy_cfg = {}; struct power_supply_config psy_cfg = {};
struct axp20x_usb_power *power; struct axp20x_usb_power *power;
static const char * const irq_names[] = { "VBUS_PLUGIN", static const char * const axp20x_irq_names[] = { "VBUS_PLUGIN",
"VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID" }; "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; int i, irq, ret;
if (!of_device_is_available(pdev->dev.of_node)) if (!of_device_is_available(pdev->dev.of_node))
...@@ -185,31 +214,47 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) ...@@ -185,31 +214,47 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
if (!power) if (!power)
return -ENOMEM; return -ENOMEM;
power->np = pdev->dev.of_node;
power->regmap = axp20x->regmap; power->regmap = axp20x->regmap;
/* Enable vbus valid checking */ if (of_device_is_compatible(power->np,
ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, "x-powers,axp202-usb-power-supply")) {
AXP20X_VBUS_MON_VBUS_VALID, AXP20X_VBUS_MON_VBUS_VALID); /* Enable vbus valid checking */
if (ret) ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
return ret; AXP20X_VBUS_MON_VBUS_VALID,
AXP20X_VBUS_MON_VBUS_VALID);
if (ret)
return ret;
/* Enable vbus voltage and current measurement */ /* Enable vbus voltage and current measurement */
ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, 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,
AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT); AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT);
if (ret) if (ret)
return 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.of_node = pdev->dev.of_node;
psy_cfg.drv_data = power; psy_cfg.drv_data = power;
power->supply = devm_power_supply_register(&pdev->dev, power->supply = devm_power_supply_register(&pdev->dev, usb_power_desc,
&axp20x_usb_power_desc, &psy_cfg); &psy_cfg);
if (IS_ERR(power->supply)) if (IS_ERR(power->supply))
return PTR_ERR(power->supply); return PTR_ERR(power->supply);
/* Request irqs after registering, as irqs may trigger immediately */ /* 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]); irq = platform_get_irq_byname(pdev, irq_names[i]);
if (irq < 0) { if (irq < 0) {
dev_warn(&pdev->dev, "No IRQ for %s: %d\n", dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
...@@ -229,6 +274,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) ...@@ -229,6 +274,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
static const struct of_device_id axp20x_usb_power_match[] = { static const struct of_device_id axp20x_usb_power_match[] = {
{ .compatible = "x-powers,axp202-usb-power-supply" }, { .compatible = "x-powers,axp202-usb-power-supply" },
{ .compatible = "x-powers,axp221-usb-power-supply" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
* *
* These are indexes into a device's register mapping array. * These are indexes into a device's register mapping array.
*/ */
enum bq27xxx_reg_index { enum bq27xxx_reg_index {
BQ27XXX_REG_CTRL = 0, /* Control */ BQ27XXX_REG_CTRL = 0, /* Control */
BQ27XXX_REG_TEMP, /* Temperature */ BQ27XXX_REG_TEMP, /* Temperature */
...@@ -100,157 +101,144 @@ enum bq27xxx_reg_index { ...@@ -100,157 +101,144 @@ enum bq27xxx_reg_index {
BQ27XXX_REG_SOC, /* State-of-Charge */ BQ27XXX_REG_SOC, /* State-of-Charge */
BQ27XXX_REG_DCAP, /* Design Capacity */ BQ27XXX_REG_DCAP, /* Design Capacity */
BQ27XXX_REG_AP, /* Average Power */ BQ27XXX_REG_AP, /* Average Power */
BQ27XXX_REG_MAX, /* sentinel */
}; };
/* Register mappings */ /* Register mappings */
static u8 bq27000_regs[] = { static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
0x00, /* CONTROL */ [BQ27000] = {
0x06, /* TEMP */ [BQ27XXX_REG_CTRL] = 0x00,
INVALID_REG_ADDR, /* INT TEMP - NA*/ [BQ27XXX_REG_TEMP] = 0x06,
0x08, /* VOLT */ [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
0x14, /* AVG CURR */ [BQ27XXX_REG_VOLT] = 0x08,
0x0a, /* FLAGS */ [BQ27XXX_REG_AI] = 0x14,
0x16, /* TTE */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x18, /* TTF */ [BQ27XXX_REG_TTE] = 0x16,
0x1c, /* TTES */ [BQ27XXX_REG_TTF] = 0x18,
0x26, /* TTECP */ [BQ27XXX_REG_TTES] = 0x1c,
0x0c, /* NAC */ [BQ27XXX_REG_TTECP] = 0x26,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_NAC] = 0x0c,
0x2a, /* CYCT */ [BQ27XXX_REG_FCC] = 0x12,
0x22, /* AE */ [BQ27XXX_REG_CYCT] = 0x2a,
0x0b, /* SOC(RSOC) */ [BQ27XXX_REG_AE] = 0x22,
0x76, /* DCAP(ILMD) */ [BQ27XXX_REG_SOC] = 0x0b,
0x24, /* AP */ [BQ27XXX_REG_DCAP] = 0x76,
}; [BQ27XXX_REG_AP] = 0x24,
},
static u8 bq27010_regs[] = { [BQ27010] = {
0x00, /* CONTROL */ [BQ27XXX_REG_CTRL] = 0x00,
0x06, /* TEMP */ [BQ27XXX_REG_TEMP] = 0x06,
INVALID_REG_ADDR, /* INT TEMP - NA*/ [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
0x08, /* VOLT */ [BQ27XXX_REG_VOLT] = 0x08,
0x14, /* AVG CURR */ [BQ27XXX_REG_AI] = 0x14,
0x0a, /* FLAGS */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x16, /* TTE */ [BQ27XXX_REG_TTE] = 0x16,
0x18, /* TTF */ [BQ27XXX_REG_TTF] = 0x18,
0x1c, /* TTES */ [BQ27XXX_REG_TTES] = 0x1c,
0x26, /* TTECP */ [BQ27XXX_REG_TTECP] = 0x26,
0x0c, /* NAC */ [BQ27XXX_REG_NAC] = 0x0c,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_FCC] = 0x12,
0x2a, /* CYCT */ [BQ27XXX_REG_CYCT] = 0x2a,
INVALID_REG_ADDR, /* AE - NA */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
0x0b, /* SOC(RSOC) */ [BQ27XXX_REG_SOC] = 0x0b,
0x76, /* DCAP(ILMD) */ [BQ27XXX_REG_DCAP] = 0x76,
INVALID_REG_ADDR, /* AP - NA */ [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
}; },
[BQ27500] = {
static u8 bq27500_regs[] = { [BQ27XXX_REG_CTRL] = 0x00,
0x00, /* CONTROL */ [BQ27XXX_REG_TEMP] = 0x06,
0x06, /* TEMP */ [BQ27XXX_REG_INT_TEMP] = 0x28,
0x28, /* INT TEMP */ [BQ27XXX_REG_VOLT] = 0x08,
0x08, /* VOLT */ [BQ27XXX_REG_AI] = 0x14,
0x14, /* AVG CURR */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x0a, /* FLAGS */ [BQ27XXX_REG_TTE] = 0x16,
0x16, /* TTE */ [BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTF - NA */ [BQ27XXX_REG_TTES] = 0x1a,
0x1a, /* TTES */ [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTECP - NA */ [BQ27XXX_REG_NAC] = 0x0c,
0x0c, /* NAC */ [BQ27XXX_REG_FCC] = 0x12,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_CYCT] = 0x2a,
0x2a, /* CYCT */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* AE - NA */ [BQ27XXX_REG_SOC] = 0x2c,
0x2c, /* SOC(RSOC) */ [BQ27XXX_REG_DCAP] = 0x3c,
0x3c, /* DCAP(ILMD) */ [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* AP - NA */ },
}; [BQ27530] = {
[BQ27XXX_REG_CTRL] = 0x00,
static u8 bq27530_regs[] = { [BQ27XXX_REG_TEMP] = 0x06,
0x00, /* CONTROL */ [BQ27XXX_REG_INT_TEMP] = 0x32,
0x06, /* TEMP */ [BQ27XXX_REG_VOLT] = 0x08,
0x32, /* INT TEMP */ [BQ27XXX_REG_AI] = 0x14,
0x08, /* VOLT */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x14, /* AVG CURR */ [BQ27XXX_REG_TTE] = 0x16,
0x0a, /* FLAGS */ [BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
0x16, /* TTE */ [BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTF - NA */ [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTES - NA */ [BQ27XXX_REG_NAC] = 0x0c,
INVALID_REG_ADDR, /* TTECP - NA */ [BQ27XXX_REG_FCC] = 0x12,
0x0c, /* NAC */ [BQ27XXX_REG_CYCT] = 0x2a,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
0x2a, /* CYCT */ [BQ27XXX_REG_SOC] = 0x2c,
INVALID_REG_ADDR, /* AE - NA */ [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
0x2c, /* SOC(RSOC) */ [BQ27XXX_REG_AP] = 0x24,
INVALID_REG_ADDR, /* DCAP - NA */ },
0x24, /* AP */ [BQ27541] = {
}; [BQ27XXX_REG_CTRL] = 0x00,
[BQ27XXX_REG_TEMP] = 0x06,
static u8 bq27541_regs[] = { [BQ27XXX_REG_INT_TEMP] = 0x28,
0x00, /* CONTROL */ [BQ27XXX_REG_VOLT] = 0x08,
0x06, /* TEMP */ [BQ27XXX_REG_AI] = 0x14,
0x28, /* INT TEMP */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x08, /* VOLT */ [BQ27XXX_REG_TTE] = 0x16,
0x14, /* AVG CURR */ [BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
0x0a, /* FLAGS */ [BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
0x16, /* TTE */ [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTF - NA */ [BQ27XXX_REG_NAC] = 0x0c,
INVALID_REG_ADDR, /* TTES - NA */ [BQ27XXX_REG_FCC] = 0x12,
INVALID_REG_ADDR, /* TTECP - NA */ [BQ27XXX_REG_CYCT] = 0x2a,
0x0c, /* NAC */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_SOC] = 0x2c,
0x2a, /* CYCT */ [BQ27XXX_REG_DCAP] = 0x3c,
INVALID_REG_ADDR, /* AE - NA */ [BQ27XXX_REG_AP] = 0x24,
0x2c, /* SOC(RSOC) */ },
0x3c, /* DCAP */ [BQ27545] = {
0x24, /* AP */ [BQ27XXX_REG_CTRL] = 0x00,
}; [BQ27XXX_REG_TEMP] = 0x06,
[BQ27XXX_REG_INT_TEMP] = 0x28,
static u8 bq27545_regs[] = { [BQ27XXX_REG_VOLT] = 0x08,
0x00, /* CONTROL */ [BQ27XXX_REG_AI] = 0x14,
0x06, /* TEMP */ [BQ27XXX_REG_FLAGS] = 0x0a,
0x28, /* INT TEMP */ [BQ27XXX_REG_TTE] = 0x16,
0x08, /* VOLT */ [BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
0x14, /* AVG CURR */ [BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
0x0a, /* FLAGS */ [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
0x16, /* TTE */ [BQ27XXX_REG_NAC] = 0x0c,
INVALID_REG_ADDR, /* TTF - NA */ [BQ27XXX_REG_FCC] = 0x12,
INVALID_REG_ADDR, /* TTES - NA */ [BQ27XXX_REG_CYCT] = 0x2a,
INVALID_REG_ADDR, /* TTECP - NA */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
0x0c, /* NAC */ [BQ27XXX_REG_SOC] = 0x2c,
0x12, /* LMD(FCC) */ [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
0x2a, /* CYCT */ [BQ27XXX_REG_AP] = 0x24,
INVALID_REG_ADDR, /* AE - NA */ },
0x2c, /* SOC(RSOC) */ [BQ27421] = {
INVALID_REG_ADDR, /* DCAP - NA */ [BQ27XXX_REG_CTRL] = 0x00,
0x24, /* AP */ [BQ27XXX_REG_TEMP] = 0x02,
}; [BQ27XXX_REG_INT_TEMP] = 0x1e,
[BQ27XXX_REG_VOLT] = 0x04,
static u8 bq27421_regs[] = { [BQ27XXX_REG_AI] = 0x10,
0x00, /* CONTROL */ [BQ27XXX_REG_FLAGS] = 0x06,
0x02, /* TEMP */ [BQ27XXX_REG_TTE] = INVALID_REG_ADDR,
0x1e, /* INT TEMP */ [BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
0x04, /* VOLT */ [BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
0x10, /* AVG CURR */ [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
0x06, /* FLAGS */ [BQ27XXX_REG_NAC] = 0x08,
INVALID_REG_ADDR, /* TTE - NA */ [BQ27XXX_REG_FCC] = 0x0e,
INVALID_REG_ADDR, /* TTF - NA */ [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTES - NA */ [BQ27XXX_REG_AE] = INVALID_REG_ADDR,
INVALID_REG_ADDR, /* TTECP - NA */ [BQ27XXX_REG_SOC] = 0x1c,
0x08, /* NAC */ [BQ27XXX_REG_DCAP] = 0x3c,
0x0e, /* FCC */ [BQ27XXX_REG_AP] = 0x18,
INVALID_REG_ADDR, /* CYCT - NA */ },
INVALID_REG_ADDR, /* AE - NA */
0x1c, /* SOC */
0x3c, /* DCAP */
0x18, /* AP */
};
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 enum power_supply_property bq27000_battery_props[] = { static enum power_supply_property bq27000_battery_props[] = {
......
/* /*
* SCI Reset driver for Keystone based devices * BQ27xxx battery monitor I2C driver
* *
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
......
This diff is collapsed.
...@@ -491,8 +491,11 @@ int power_supply_get_property(struct power_supply *psy, ...@@ -491,8 +491,11 @@ int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp, enum power_supply_property psp,
union power_supply_propval *val) 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 -ENODEV;
}
return psy->desc->get_property(psy, psp, val); return psy->desc->get_property(psy, psp, val);
} }
...@@ -785,6 +788,7 @@ __power_supply_register(struct device *parent, ...@@ -785,6 +788,7 @@ __power_supply_register(struct device *parent,
* after calling power_supply_register()). * after calling power_supply_register()).
*/ */
atomic_inc(&psy->use_cnt); atomic_inc(&psy->use_cnt);
psy->initialized = true;
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
&psy->deferred_register_work, &psy->deferred_register_work,
......
...@@ -83,7 +83,7 @@ static ssize_t power_supply_show_property(struct device *dev, ...@@ -83,7 +83,7 @@ static ssize_t power_supply_show_property(struct device *dev,
if (ret == -ENODATA) if (ret == -ENODATA)
dev_dbg(dev, "driver has no data for `%s' property\n", dev_dbg(dev, "driver has no data for `%s' property\n",
attr->attr.name); attr->attr.name);
else if (ret != -ENODEV) else if (ret != -ENODEV && ret != -EAGAIN)
dev_err(dev, "driver failed to report `%s' property: %zd\n", dev_err(dev, "driver failed to report `%s' property: %zd\n",
attr->attr.name, ret); attr->attr.name, ret);
return ret; return ret;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/extcon.h>
#define SMBB_CHG_VMAX 0x040 #define SMBB_CHG_VMAX 0x040
#define SMBB_CHG_VSAFE 0x041 #define SMBB_CHG_VSAFE 0x041
...@@ -111,6 +112,7 @@ struct smbb_charger { ...@@ -111,6 +112,7 @@ struct smbb_charger {
unsigned int revision; unsigned int revision;
unsigned int addr; unsigned int addr;
struct device *dev; struct device *dev;
struct extcon_dev *edev;
bool dc_disabled; bool dc_disabled;
bool jeita_ext_temp; bool jeita_ext_temp;
...@@ -125,6 +127,11 @@ struct smbb_charger { ...@@ -125,6 +127,11 @@ struct smbb_charger {
struct regmap *regmap; struct regmap *regmap;
}; };
static const unsigned int smbb_usb_extcon_cable[] = {
EXTCON_USB,
EXTCON_NONE,
};
static int smbb_vbat_weak_fn(unsigned int index) static int smbb_vbat_weak_fn(unsigned int index)
{ {
return 2100000 + index * 100000; return 2100000 + index * 100000;
...@@ -371,6 +378,8 @@ static irqreturn_t smbb_usb_valid_handler(int irq, void *_data) ...@@ -371,6 +378,8 @@ static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
struct smbb_charger *chg = _data; struct smbb_charger *chg = _data;
smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); 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); power_supply_changed(chg->usb_psy);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -849,6 +858,18 @@ static int smbb_charger_probe(struct platform_device *pdev) ...@@ -849,6 +858,18 @@ static int smbb_charger_probe(struct platform_device *pdev)
return PTR_ERR(chg->usb_psy); 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) { if (!chg->dc_disabled) {
dc_cfg.drv_data = chg; dc_cfg.drv_data = chg;
dc_cfg.supplied_to = smbb_bif; dc_cfg.supplied_to = smbb_bif;
......
...@@ -148,7 +148,8 @@ config POWER_RESET_XGENE ...@@ -148,7 +148,8 @@ config POWER_RESET_XGENE
config POWER_RESET_KEYSTONE config POWER_RESET_KEYSTONE
bool "Keystone reset driver" bool "Keystone reset driver"
depends on ARCH_KEYSTONE depends on ARCH_KEYSTONE || COMPILE_TEST
depends on HAS_IOMEM
select MFD_SYSCON select MFD_SYSCON
help help
Reboot support for the KEYSTONE SoCs. Reboot support for the KEYSTONE SoCs.
...@@ -183,5 +184,19 @@ config POWER_RESET_ZX ...@@ -183,5 +184,19 @@ config POWER_RESET_ZX
help help
Reboot support for ZTE SoCs. 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 endif
...@@ -21,3 +21,5 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o ...@@ -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_SYSCON_POWEROFF) += syscon-poweroff.o
obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.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
/*
* 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 <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/reboot.h>
#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 <andy.yan@rock-chips.com");
MODULE_DESCRIPTION("System reboot mode core library");
MODULE_LICENSE("GPL v2");
#ifndef __REBOOT_MODE_H__
#define __REBOOT_MODE_H__
struct reboot_mode_driver {
struct device *dev;
struct list_head head;
int (*write)(struct reboot_mode_driver *reboot, unsigned int magic);
struct notifier_block reboot_notifier;
};
int reboot_mode_register(struct reboot_mode_driver *reboot);
int reboot_mode_unregister(struct reboot_mode_driver *reboot);
#endif
...@@ -30,7 +30,7 @@ static struct regmap *map; ...@@ -30,7 +30,7 @@ static struct regmap *map;
static u32 offset; static u32 offset;
static u32 mask; static u32 mask;
void syscon_poweroff(void) static void syscon_poweroff(void)
{ {
/* Issue the poweroff */ /* Issue the poweroff */
regmap_write(map, offset, mask); regmap_write(map, offset, mask);
......
/*
* 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 <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#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 <andy.yan@rock-chips.com");
MODULE_DESCRIPTION("SYSCON reboot mode driver");
MODULE_LICENSE("GPL v2");
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
struct max8903_pdata { struct max8903_pdata {
/* /*
* GPIOs * GPIOs
* cen, chg, flt, and usus are optional. * cen, chg, flt, dcm and usus are optional.
* dok, dcm, and uok are not optional depending on the status of * dok and uok are not optional depending on the status of
* dc_valid and usb_valid. * dc_valid and usb_valid.
*/ */
int cen; /* Charger Enable input */ int cen; /* Charger Enable input */
...@@ -41,7 +41,7 @@ struct max8903_pdata { ...@@ -41,7 +41,7 @@ struct max8903_pdata {
/* /*
* DC(Adapter/TA) is wired * DC(Adapter/TA) is wired
* When dc_valid is true, * 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. * At least one of dc_valid or usb_valid should be true.
*/ */
......
...@@ -248,6 +248,7 @@ struct power_supply { ...@@ -248,6 +248,7 @@ struct power_supply {
struct delayed_work deferred_register_work; struct delayed_work deferred_register_work;
spinlock_t changed_lock; spinlock_t changed_lock;
bool changed; bool changed;
bool initialized;
atomic_t use_cnt; atomic_t use_cnt;
#ifdef CONFIG_THERMAL #ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd; struct thermal_zone_device *tzd;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment