power supply and reset changes for the v4.8 series
* introduce reboot mode driver * add DT support to max8903 * add power supply support for axp221 * misc. fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJXlm+bAAoJENju1/PIO/qaHCsP/0bwvb3PlvPozVs7iXba4hbK It6RxQDHl9Q0tvsgRitqoibomBlGqdMXADwr2yXsio255IYqNTKErJasiOn0KkO6 Wuoo9FSiZV6KL1JMBvZOgMydK/x8q2yBKKJKm9JG9srLueJWuZa/4BqOWS4JSFJ6 xlevxxA0XqUzWr6VUXFRTd/YXa0OaRDHaG9JN1NN8qvJWvvYZJLhpDzWdDu83KzU CPEP7g8UeOFLylcmjeHgT9rJuiHbd6UCr4yKjFqLvM6uM9SY/Uinz62u4tKL5zcp /9V4oo8/9RjJnG/gkm4ozAL2Rb1fpeajTZivUX3t+CiEV4Nc8xiQMCMDI2nKSqr4 IF9nghYub+q6q7EfonWZ22Aa6VhGdI6ToG5iK3euag2vkypLYe9GD1tPyAnnxx1o xlnziiveGKcKwSIY3tTOFVAoGqhCWIpM06ZC7/Y9HvM6EPhAr4q4Pq1xNFwr0Rrs OoEobm5cRB7IUtu2Gl0GU/Ku5mDoen2LvSVzIjF36/aGN+atpd7Tkoam7LBtedZA aqsEV/qMfgsIUYWj5/lmLZOQuG6viEou/BWvQz8cczA0U2mFDcgY6UCLMwVeJ7sj ZT+1uVoupcO5UNEULwdzufUmaC0ze7HrGNeXZZwt5S1IWqNsRg71FzqFYYaIwZGy Rnt3P3tSqhxZrz1xeZ6r =bMvA -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f7816ad0f8
25
Documentation/devicetree/bindings/power/max8903-charger.txt
Normal file
25
Documentation/devicetree/bindings/power/max8903-charger.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
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";
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
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>;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
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>;
|
||||
};
|
||||
};
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -9169,6 +9169,8 @@ M: David Woodhouse <dwmw2@infradead.org>
|
|||
L: linux-pm@vger.kernel.org
|
||||
T: git git://git.infradead.org/battery-2.6.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/power/
|
||||
F: Documentation/devicetree/bindings/power_supply/
|
||||
F: include/linux/power_supply.h
|
||||
F: drivers/power/
|
||||
X: drivers/power/avs/
|
||||
|
|
|
@ -394,6 +394,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
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) {
|
||||
val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
|
|
@ -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[] = {
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
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[] = {
|
||||
|
|
|
@ -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 <afd@ti.com>
|
||||
|
|
|
@ -23,13 +23,16 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power/max8903_charger.h>
|
||||
|
||||
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 +56,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 (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)
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
@ -75,13 +78,14 @@ static int max8903_get_property(struct power_supply *psy,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -93,11 +97,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));
|
||||
|
||||
|
@ -122,7 +126,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;
|
||||
|
||||
|
@ -136,7 +140,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));
|
||||
|
||||
|
@ -161,7 +165,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;
|
||||
|
@ -179,57 +183,109 @@ static irqreturn_t max8903_fault(int irq, void *_data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int max8903_probe(struct platform_device *pdev)
|
||||
static struct max8903_pdata *max8903_parse_dt_data(struct device *dev)
|
||||
{
|
||||
struct max8903_data *data;
|
||||
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);
|
||||
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;
|
||||
|
||||
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->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) &&
|
||||
pdata->dcm && gpio_is_valid(pdata->dcm)) {
|
||||
if (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;
|
||||
|
||||
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, "When DC is wired, DOK should be wired as well.\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 (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) {
|
||||
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 {
|
||||
|
@ -239,33 +295,45 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (pdata->cen) {
|
||||
if (gpio_is_valid(pdata->cen)) {
|
||||
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 (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->chg) {
|
||||
if (!gpio_is_valid(pdata->chg)) {
|
||||
dev_err(dev, "Invalid pin: chg.\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->flt) {
|
||||
if (!gpio_is_valid(pdata->flt)) {
|
||||
dev_err(dev, "Invalid pin: flt.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,14 +341,52 @@ 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;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
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);
|
||||
|
@ -315,7 +421,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 |
|
||||
|
@ -331,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
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -785,6 +788,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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/extcon.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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.
|
||||
|
@ -183,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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
140
drivers/power/reset/reboot-mode.c
Normal file
140
drivers/power/reset/reboot-mode.c
Normal file
|
@ -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 <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");
|
14
drivers/power/reset/reboot-mode.h
Normal file
14
drivers/power/reset/reboot-mode.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#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;
|
|||
static u32 offset;
|
||||
static u32 mask;
|
||||
|
||||
void syscon_poweroff(void)
|
||||
static void syscon_poweroff(void)
|
||||
{
|
||||
/* Issue the poweroff */
|
||||
regmap_write(map, offset, mask);
|
||||
|
|
99
drivers/power/reset/syscon-reboot-mode.c
Normal file
99
drivers/power/reset/syscon-reboot-mode.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 @@
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user