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:
Linus Torvalds 2016-07-26 19:49:09 -07:00
commit f7816ad0f8
22 changed files with 779 additions and 247 deletions

View 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";
};

View File

@ -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>;
}

View File

@ -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>;
};
};

View File

@ -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.

View File

@ -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/

View File

@ -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

View File

@ -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);

View File

@ -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[] = {

View File

@ -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>

View File

@ -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
},
};

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View 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");

View 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

View File

@ -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);

View 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");

View File

@ -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.
*/

View File

@ -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;