diff options
22 files changed, 775 insertions, 243 deletions
diff --git a/Documentation/devicetree/bindings/power/max8903-charger.txt b/Documentation/devicetree/bindings/power/max8903-charger.txt new file mode 100644 index 000000000000..f0f4e12b076e --- /dev/null +++ b/Documentation/devicetree/bindings/power/max8903-charger.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | Maxim Semiconductor MAX8903 Battery Charger bindings | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "maxim,max8903" for MAX8903 Battery Charger | ||
| 5 | - dok-gpios: Valid DC power has been detected (active low, input), optional if uok-gpios is provided | ||
| 6 | - uok-gpios: Valid USB power has been detected (active low, input), optional if dok-gpios is provided | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | - cen-gpios: Charge enable pin (active low, output) | ||
| 10 | - chg-gpios: Charger status pin (active low, input) | ||
| 11 | - flt-gpios: Fault pin (active low, output) | ||
| 12 | - dcm-gpios: Current limit mode setting (DC=1 or USB=0, output) | ||
| 13 | - usus-gpios: USB suspend pin (active high, output) | ||
| 14 | |||
| 15 | |||
| 16 | Example: | ||
| 17 | |||
| 18 | max8903-charger { | ||
| 19 | compatible = "maxim,max8903"; | ||
| 20 | dok-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; | ||
| 21 | flt-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; | ||
| 22 | chg-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; | ||
| 23 | cen-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; | ||
| 24 | status = "okay"; | ||
| 25 | }; | ||
diff --git a/Documentation/devicetree/bindings/reset/brcm,bcm21664-resetmgr.txt b/Documentation/devicetree/bindings/power/reset/brcm,bcm21664-resetmgr.txt index 93f31ca1ef4b..93f31ca1ef4b 100644 --- a/Documentation/devicetree/bindings/reset/brcm,bcm21664-resetmgr.txt +++ b/Documentation/devicetree/bindings/power/reset/brcm,bcm21664-resetmgr.txt | |||
diff --git a/Documentation/devicetree/bindings/power/reset/reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt new file mode 100644 index 000000000000..de34f27d509e --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | Generic reboot mode core map driver | ||
| 2 | |||
| 3 | This driver get reboot mode arguments and call the write | ||
| 4 | interface to store the magic value in special register | ||
| 5 | or ram. Then the bootloader can read it and take different | ||
| 6 | action according to the argument stored. | ||
| 7 | |||
| 8 | All mode properties are vendor specific, it is a indication to tell | ||
| 9 | the bootloader what to do when the system reboots, and should be named | ||
| 10 | as mode-xxx = <magic> (xxx is mode name, magic should be a none-zero value). | ||
| 11 | |||
| 12 | For example modes common on Android platform: | ||
| 13 | - mode-normal: Normal reboot mode, system reboot with command "reboot". | ||
| 14 | - mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image. | ||
| 15 | - mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device. | ||
| 16 | - mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform, | ||
| 17 | usually used in development. | ||
| 18 | |||
| 19 | Example: | ||
| 20 | reboot-mode { | ||
| 21 | mode-normal = <BOOT_NORMAL>; | ||
| 22 | mode-recovery = <BOOT_RECOVERY>; | ||
| 23 | mode-bootloader = <BOOT_FASTBOOT>; | ||
| 24 | mode-loader = <BOOT_BL_DOWNLOAD>; | ||
| 25 | } | ||
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt new file mode 100644 index 000000000000..f7ce1d8af04a --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | SYSCON reboot mode driver | ||
| 2 | |||
| 3 | This driver gets reboot mode magic value form reboot-mode driver | ||
| 4 | and stores it in a SYSCON mapped register. Then the bootloader | ||
| 5 | can read it and take different action according to the magic | ||
| 6 | value stored. | ||
| 7 | |||
| 8 | This DT node should be represented as a sub-node of a "syscon", "simple-mfd" | ||
| 9 | node. | ||
| 10 | |||
| 11 | Required properties: | ||
| 12 | - compatible: should be "syscon-reboot-mode" | ||
| 13 | - offset: offset in the register map for the storage register (in bytes) | ||
| 14 | |||
| 15 | Optional property: | ||
| 16 | - mask: bits mask of the bits in the register to store the reboot mode magic value, | ||
| 17 | default set to 0xffffffff if missing. | ||
| 18 | |||
| 19 | The rest of the properties should follow the generic reboot-mode description | ||
| 20 | found in reboot-mode.txt | ||
| 21 | |||
| 22 | Example: | ||
| 23 | pmu: pmu@20004000 { | ||
| 24 | compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; | ||
| 25 | reg = <0x20004000 0x100>; | ||
| 26 | |||
| 27 | reboot-mode { | ||
| 28 | compatible = "syscon-reboot-mode"; | ||
| 29 | offset = <0x40>; | ||
| 30 | mode-normal = <BOOT_NORMAL>; | ||
| 31 | mode-recovery = <BOOT_RECOVERY>; | ||
| 32 | mode-bootloader = <BOOT_FASTBOOT>; | ||
| 33 | mode-loader = <BOOT_BL_DOWNLOAD>; | ||
| 34 | }; | ||
| 35 | }; | ||
diff --git a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt b/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt index 862f4a49dc49..f1d7beec45bf 100644 --- a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt +++ b/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | AXP20x USB power supply | 1 | AXP20x USB power supply |
| 2 | 2 | ||
| 3 | Required Properties: | 3 | Required Properties: |
| 4 | -compatible: "x-powers,axp202-usb-power-supply" | 4 | -compatible: One of: "x-powers,axp202-usb-power-supply" |
| 5 | "x-powers,axp221-usb-power-supply" | ||
| 5 | 6 | ||
| 6 | This node is a subnode of the axp20x PMIC. | 7 | This node is a subnode of the axp20x PMIC. |
| 7 | 8 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index b407c5f5caa4..771c31c73172 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -9169,6 +9169,8 @@ M: David Woodhouse <dwmw2@infradead.org> | |||
| 9169 | L: linux-pm@vger.kernel.org | 9169 | L: linux-pm@vger.kernel.org |
| 9170 | T: git git://git.infradead.org/battery-2.6.git | 9170 | T: git git://git.infradead.org/battery-2.6.git |
| 9171 | S: Maintained | 9171 | S: Maintained |
| 9172 | F: Documentation/devicetree/bindings/power/ | ||
| 9173 | F: Documentation/devicetree/bindings/power_supply/ | ||
| 9172 | F: include/linux/power_supply.h | 9174 | F: include/linux/power_supply.h |
| 9173 | F: drivers/power/ | 9175 | F: drivers/power/ |
| 9174 | X: drivers/power/avs/ | 9176 | X: drivers/power/avs/ |
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 0f11a0f4c369..acd4a1524a1e 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
| @@ -394,6 +394,7 @@ config CHARGER_QCOM_SMBB | |||
| 394 | tristate "Qualcomm Switch-Mode Battery Charger and Boost" | 394 | tristate "Qualcomm Switch-Mode Battery Charger and Boost" |
| 395 | depends on MFD_SPMI_PMIC || COMPILE_TEST | 395 | depends on MFD_SPMI_PMIC || COMPILE_TEST |
| 396 | depends on OF | 396 | depends on OF |
| 397 | depends on EXTCON | ||
| 397 | help | 398 | help |
| 398 | Say Y to include support for the Switch-Mode Battery Charger and | 399 | Say Y to include support for the Switch-Mode Battery Charger and |
| 399 | Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger | 400 | Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger |
diff --git a/drivers/power/axp20x_usb_power.c b/drivers/power/axp20x_usb_power.c index 421a90b83567..6af6feb7058d 100644 --- a/drivers/power/axp20x_usb_power.c +++ b/drivers/power/axp20x_usb_power.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #define AXP20X_VBUS_MON_VBUS_VALID BIT(3) | 42 | #define AXP20X_VBUS_MON_VBUS_VALID BIT(3) |
| 43 | 43 | ||
| 44 | struct axp20x_usb_power { | 44 | struct axp20x_usb_power { |
| 45 | struct device_node *np; | ||
| 45 | struct regmap *regmap; | 46 | struct regmap *regmap; |
| 46 | struct power_supply *supply; | 47 | struct power_supply *supply; |
| 47 | }; | 48 | }; |
| @@ -85,7 +86,12 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, | |||
| 85 | 86 | ||
| 86 | switch (v & AXP20X_VBUS_CLIMIT_MASK) { | 87 | switch (v & AXP20X_VBUS_CLIMIT_MASK) { |
| 87 | case AXP20X_VBUC_CLIMIT_100mA: | 88 | case AXP20X_VBUC_CLIMIT_100mA: |
| 88 | val->intval = 100000; | 89 | if (of_device_is_compatible(power->np, |
| 90 | "x-powers,axp202-usb-power-supply")) { | ||
| 91 | val->intval = 100000; | ||
| 92 | } else { | ||
| 93 | val->intval = -1; /* No 100mA limit */ | ||
| 94 | } | ||
| 89 | break; | 95 | break; |
| 90 | case AXP20X_VBUC_CLIMIT_500mA: | 96 | case AXP20X_VBUC_CLIMIT_500mA: |
| 91 | val->intval = 500000; | 97 | val->intval = 500000; |
| @@ -122,16 +128,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, | |||
| 122 | break; | 128 | break; |
| 123 | } | 129 | } |
| 124 | 130 | ||
| 125 | ret = regmap_read(power->regmap, AXP20X_USB_OTG_STATUS, &v); | 131 | val->intval = POWER_SUPPLY_HEALTH_GOOD; |
| 126 | if (ret) | ||
| 127 | return ret; | ||
| 128 | 132 | ||
| 129 | if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) { | 133 | if (of_device_is_compatible(power->np, |
| 130 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | 134 | "x-powers,axp202-usb-power-supply")) { |
| 131 | break; | 135 | ret = regmap_read(power->regmap, |
| 132 | } | 136 | AXP20X_USB_OTG_STATUS, &v); |
| 137 | if (ret) | ||
| 138 | return ret; | ||
| 133 | 139 | ||
| 134 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | 140 | if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) |
| 141 | val->intval = | ||
| 142 | POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
| 143 | } | ||
| 135 | break; | 144 | break; |
| 136 | case POWER_SUPPLY_PROP_PRESENT: | 145 | case POWER_SUPPLY_PROP_PRESENT: |
| 137 | val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); | 146 | val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); |
| @@ -156,6 +165,14 @@ static enum power_supply_property axp20x_usb_power_properties[] = { | |||
| 156 | POWER_SUPPLY_PROP_CURRENT_NOW, | 165 | POWER_SUPPLY_PROP_CURRENT_NOW, |
| 157 | }; | 166 | }; |
| 158 | 167 | ||
| 168 | static enum power_supply_property axp22x_usb_power_properties[] = { | ||
| 169 | POWER_SUPPLY_PROP_HEALTH, | ||
| 170 | POWER_SUPPLY_PROP_PRESENT, | ||
| 171 | POWER_SUPPLY_PROP_ONLINE, | ||
| 172 | POWER_SUPPLY_PROP_VOLTAGE_MIN, | ||
| 173 | POWER_SUPPLY_PROP_CURRENT_MAX, | ||
| 174 | }; | ||
| 175 | |||
| 159 | static const struct power_supply_desc axp20x_usb_power_desc = { | 176 | static const struct power_supply_desc axp20x_usb_power_desc = { |
| 160 | .name = "axp20x-usb", | 177 | .name = "axp20x-usb", |
| 161 | .type = POWER_SUPPLY_TYPE_USB, | 178 | .type = POWER_SUPPLY_TYPE_USB, |
| @@ -164,13 +181,25 @@ static const struct power_supply_desc axp20x_usb_power_desc = { | |||
| 164 | .get_property = axp20x_usb_power_get_property, | 181 | .get_property = axp20x_usb_power_get_property, |
| 165 | }; | 182 | }; |
| 166 | 183 | ||
| 184 | static const struct power_supply_desc axp22x_usb_power_desc = { | ||
| 185 | .name = "axp20x-usb", | ||
| 186 | .type = POWER_SUPPLY_TYPE_USB, | ||
| 187 | .properties = axp22x_usb_power_properties, | ||
| 188 | .num_properties = ARRAY_SIZE(axp22x_usb_power_properties), | ||
| 189 | .get_property = axp20x_usb_power_get_property, | ||
| 190 | }; | ||
| 191 | |||
| 167 | static int axp20x_usb_power_probe(struct platform_device *pdev) | 192 | static int axp20x_usb_power_probe(struct platform_device *pdev) |
| 168 | { | 193 | { |
| 169 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); | 194 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); |
| 170 | struct power_supply_config psy_cfg = {}; | 195 | struct power_supply_config psy_cfg = {}; |
| 171 | struct axp20x_usb_power *power; | 196 | struct axp20x_usb_power *power; |
| 172 | static const char * const irq_names[] = { "VBUS_PLUGIN", | 197 | static const char * const axp20x_irq_names[] = { "VBUS_PLUGIN", |
| 173 | "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID" }; | 198 | "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID", NULL }; |
| 199 | static const char * const axp22x_irq_names[] = { | ||
| 200 | "VBUS_PLUGIN", "VBUS_REMOVAL", NULL }; | ||
| 201 | static const char * const *irq_names; | ||
| 202 | const struct power_supply_desc *usb_power_desc; | ||
| 174 | int i, irq, ret; | 203 | int i, irq, ret; |
| 175 | 204 | ||
| 176 | if (!of_device_is_available(pdev->dev.of_node)) | 205 | if (!of_device_is_available(pdev->dev.of_node)) |
| @@ -185,31 +214,47 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) | |||
| 185 | if (!power) | 214 | if (!power) |
| 186 | return -ENOMEM; | 215 | return -ENOMEM; |
| 187 | 216 | ||
| 217 | power->np = pdev->dev.of_node; | ||
| 188 | power->regmap = axp20x->regmap; | 218 | power->regmap = axp20x->regmap; |
| 189 | 219 | ||
| 190 | /* Enable vbus valid checking */ | 220 | if (of_device_is_compatible(power->np, |
| 191 | ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, | 221 | "x-powers,axp202-usb-power-supply")) { |
| 192 | AXP20X_VBUS_MON_VBUS_VALID, AXP20X_VBUS_MON_VBUS_VALID); | 222 | /* Enable vbus valid checking */ |
| 193 | if (ret) | 223 | ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, |
| 194 | return ret; | 224 | AXP20X_VBUS_MON_VBUS_VALID, |
| 225 | AXP20X_VBUS_MON_VBUS_VALID); | ||
| 226 | if (ret) | ||
| 227 | return ret; | ||
| 195 | 228 | ||
| 196 | /* Enable vbus voltage and current measurement */ | 229 | /* Enable vbus voltage and current measurement */ |
| 197 | ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, | 230 | ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, |
| 198 | AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT, | 231 | AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT, |
| 199 | AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT); | 232 | AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT); |
| 200 | if (ret) | 233 | if (ret) |
| 201 | return ret; | 234 | return ret; |
| 235 | |||
| 236 | usb_power_desc = &axp20x_usb_power_desc; | ||
| 237 | irq_names = axp20x_irq_names; | ||
| 238 | } else if (of_device_is_compatible(power->np, | ||
| 239 | "x-powers,axp221-usb-power-supply")) { | ||
| 240 | usb_power_desc = &axp22x_usb_power_desc; | ||
| 241 | irq_names = axp22x_irq_names; | ||
| 242 | } else { | ||
| 243 | dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", | ||
| 244 | axp20x->variant); | ||
| 245 | return -EINVAL; | ||
| 246 | } | ||
| 202 | 247 | ||
| 203 | psy_cfg.of_node = pdev->dev.of_node; | 248 | psy_cfg.of_node = pdev->dev.of_node; |
| 204 | psy_cfg.drv_data = power; | 249 | psy_cfg.drv_data = power; |
| 205 | 250 | ||
| 206 | power->supply = devm_power_supply_register(&pdev->dev, | 251 | power->supply = devm_power_supply_register(&pdev->dev, usb_power_desc, |
| 207 | &axp20x_usb_power_desc, &psy_cfg); | 252 | &psy_cfg); |
| 208 | if (IS_ERR(power->supply)) | 253 | if (IS_ERR(power->supply)) |
| 209 | return PTR_ERR(power->supply); | 254 | return PTR_ERR(power->supply); |
| 210 | 255 | ||
| 211 | /* Request irqs after registering, as irqs may trigger immediately */ | 256 | /* Request irqs after registering, as irqs may trigger immediately */ |
| 212 | for (i = 0; i < ARRAY_SIZE(irq_names); i++) { | 257 | for (i = 0; irq_names[i]; i++) { |
| 213 | irq = platform_get_irq_byname(pdev, irq_names[i]); | 258 | irq = platform_get_irq_byname(pdev, irq_names[i]); |
| 214 | if (irq < 0) { | 259 | if (irq < 0) { |
| 215 | dev_warn(&pdev->dev, "No IRQ for %s: %d\n", | 260 | 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 | 274 | ||
| 230 | static const struct of_device_id axp20x_usb_power_match[] = { | 275 | static const struct of_device_id axp20x_usb_power_match[] = { |
| 231 | { .compatible = "x-powers,axp202-usb-power-supply" }, | 276 | { .compatible = "x-powers,axp202-usb-power-supply" }, |
| 277 | { .compatible = "x-powers,axp221-usb-power-supply" }, | ||
| 232 | { } | 278 | { } |
| 233 | }; | 279 | }; |
| 234 | MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); | 280 | MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); |
diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c index e90b3f307e0f..323d05a12f9b 100644 --- a/drivers/power/bq27xxx_battery.c +++ b/drivers/power/bq27xxx_battery.c | |||
| @@ -82,6 +82,7 @@ | |||
| 82 | * | 82 | * |
| 83 | * These are indexes into a device's register mapping array. | 83 | * These are indexes into a device's register mapping array. |
| 84 | */ | 84 | */ |
| 85 | |||
| 85 | enum bq27xxx_reg_index { | 86 | enum bq27xxx_reg_index { |
| 86 | BQ27XXX_REG_CTRL = 0, /* Control */ | 87 | BQ27XXX_REG_CTRL = 0, /* Control */ |
| 87 | BQ27XXX_REG_TEMP, /* Temperature */ | 88 | BQ27XXX_REG_TEMP, /* Temperature */ |
| @@ -100,157 +101,144 @@ enum bq27xxx_reg_index { | |||
| 100 | BQ27XXX_REG_SOC, /* State-of-Charge */ | 101 | BQ27XXX_REG_SOC, /* State-of-Charge */ |
| 101 | BQ27XXX_REG_DCAP, /* Design Capacity */ | 102 | BQ27XXX_REG_DCAP, /* Design Capacity */ |
| 102 | BQ27XXX_REG_AP, /* Average Power */ | 103 | BQ27XXX_REG_AP, /* Average Power */ |
| 104 | BQ27XXX_REG_MAX, /* sentinel */ | ||
| 103 | }; | 105 | }; |
| 104 | 106 | ||
| 105 | /* Register mappings */ | 107 | /* Register mappings */ |
| 106 | static u8 bq27000_regs[] = { | 108 | static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { |
| 107 | 0x00, /* CONTROL */ | 109 | [BQ27000] = { |
| 108 | 0x06, /* TEMP */ | 110 | [BQ27XXX_REG_CTRL] = 0x00, |
| 109 | INVALID_REG_ADDR, /* INT TEMP - NA*/ | 111 | [BQ27XXX_REG_TEMP] = 0x06, |
| 110 | 0x08, /* VOLT */ | 112 | [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, |
| 111 | 0x14, /* AVG CURR */ | 113 | [BQ27XXX_REG_VOLT] = 0x08, |
| 112 | 0x0a, /* FLAGS */ | 114 | [BQ27XXX_REG_AI] = 0x14, |
| 113 | 0x16, /* TTE */ | 115 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 114 | 0x18, /* TTF */ | 116 | [BQ27XXX_REG_TTE] = 0x16, |
| 115 | 0x1c, /* TTES */ | 117 | [BQ27XXX_REG_TTF] = 0x18, |
| 116 | 0x26, /* TTECP */ | 118 | [BQ27XXX_REG_TTES] = 0x1c, |
| 117 | 0x0c, /* NAC */ | 119 | [BQ27XXX_REG_TTECP] = 0x26, |
| 118 | 0x12, /* LMD(FCC) */ | 120 | [BQ27XXX_REG_NAC] = 0x0c, |
| 119 | 0x2a, /* CYCT */ | 121 | [BQ27XXX_REG_FCC] = 0x12, |
| 120 | 0x22, /* AE */ | 122 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 121 | 0x0b, /* SOC(RSOC) */ | 123 | [BQ27XXX_REG_AE] = 0x22, |
| 122 | 0x76, /* DCAP(ILMD) */ | 124 | [BQ27XXX_REG_SOC] = 0x0b, |
| 123 | 0x24, /* AP */ | 125 | [BQ27XXX_REG_DCAP] = 0x76, |
| 124 | }; | 126 | [BQ27XXX_REG_AP] = 0x24, |
| 125 | 127 | }, | |
| 126 | static u8 bq27010_regs[] = { | 128 | [BQ27010] = { |
| 127 | 0x00, /* CONTROL */ | 129 | [BQ27XXX_REG_CTRL] = 0x00, |
| 128 | 0x06, /* TEMP */ | 130 | [BQ27XXX_REG_TEMP] = 0x06, |
| 129 | INVALID_REG_ADDR, /* INT TEMP - NA*/ | 131 | [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, |
| 130 | 0x08, /* VOLT */ | 132 | [BQ27XXX_REG_VOLT] = 0x08, |
| 131 | 0x14, /* AVG CURR */ | 133 | [BQ27XXX_REG_AI] = 0x14, |
| 132 | 0x0a, /* FLAGS */ | 134 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 133 | 0x16, /* TTE */ | 135 | [BQ27XXX_REG_TTE] = 0x16, |
| 134 | 0x18, /* TTF */ | 136 | [BQ27XXX_REG_TTF] = 0x18, |
| 135 | 0x1c, /* TTES */ | 137 | [BQ27XXX_REG_TTES] = 0x1c, |
| 136 | 0x26, /* TTECP */ | 138 | [BQ27XXX_REG_TTECP] = 0x26, |
| 137 | 0x0c, /* NAC */ | 139 | [BQ27XXX_REG_NAC] = 0x0c, |
| 138 | 0x12, /* LMD(FCC) */ | 140 | [BQ27XXX_REG_FCC] = 0x12, |
| 139 | 0x2a, /* CYCT */ | 141 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 140 | INVALID_REG_ADDR, /* AE - NA */ | 142 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 141 | 0x0b, /* SOC(RSOC) */ | 143 | [BQ27XXX_REG_SOC] = 0x0b, |
| 142 | 0x76, /* DCAP(ILMD) */ | 144 | [BQ27XXX_REG_DCAP] = 0x76, |
| 143 | INVALID_REG_ADDR, /* AP - NA */ | 145 | [BQ27XXX_REG_AP] = INVALID_REG_ADDR, |
| 144 | }; | 146 | }, |
| 145 | 147 | [BQ27500] = { | |
| 146 | static u8 bq27500_regs[] = { | 148 | [BQ27XXX_REG_CTRL] = 0x00, |
| 147 | 0x00, /* CONTROL */ | 149 | [BQ27XXX_REG_TEMP] = 0x06, |
| 148 | 0x06, /* TEMP */ | 150 | [BQ27XXX_REG_INT_TEMP] = 0x28, |
| 149 | 0x28, /* INT TEMP */ | 151 | [BQ27XXX_REG_VOLT] = 0x08, |
| 150 | 0x08, /* VOLT */ | 152 | [BQ27XXX_REG_AI] = 0x14, |
| 151 | 0x14, /* AVG CURR */ | 153 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 152 | 0x0a, /* FLAGS */ | 154 | [BQ27XXX_REG_TTE] = 0x16, |
| 153 | 0x16, /* TTE */ | 155 | [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, |
| 154 | INVALID_REG_ADDR, /* TTF - NA */ | 156 | [BQ27XXX_REG_TTES] = 0x1a, |
| 155 | 0x1a, /* TTES */ | 157 | [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, |
| 156 | INVALID_REG_ADDR, /* TTECP - NA */ | 158 | [BQ27XXX_REG_NAC] = 0x0c, |
| 157 | 0x0c, /* NAC */ | 159 | [BQ27XXX_REG_FCC] = 0x12, |
| 158 | 0x12, /* LMD(FCC) */ | 160 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 159 | 0x2a, /* CYCT */ | 161 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 160 | INVALID_REG_ADDR, /* AE - NA */ | 162 | [BQ27XXX_REG_SOC] = 0x2c, |
| 161 | 0x2c, /* SOC(RSOC) */ | 163 | [BQ27XXX_REG_DCAP] = 0x3c, |
| 162 | 0x3c, /* DCAP(ILMD) */ | 164 | [BQ27XXX_REG_AP] = INVALID_REG_ADDR, |
| 163 | INVALID_REG_ADDR, /* AP - NA */ | 165 | }, |
| 164 | }; | 166 | [BQ27530] = { |
| 165 | 167 | [BQ27XXX_REG_CTRL] = 0x00, | |
| 166 | static u8 bq27530_regs[] = { | 168 | [BQ27XXX_REG_TEMP] = 0x06, |
| 167 | 0x00, /* CONTROL */ | 169 | [BQ27XXX_REG_INT_TEMP] = 0x32, |
| 168 | 0x06, /* TEMP */ | 170 | [BQ27XXX_REG_VOLT] = 0x08, |
| 169 | 0x32, /* INT TEMP */ | 171 | [BQ27XXX_REG_AI] = 0x14, |
| 170 | 0x08, /* VOLT */ | 172 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 171 | 0x14, /* AVG CURR */ | 173 | [BQ27XXX_REG_TTE] = 0x16, |
| 172 | 0x0a, /* FLAGS */ | 174 | [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, |
| 173 | 0x16, /* TTE */ | 175 | [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, |
| 174 | INVALID_REG_ADDR, /* TTF - NA */ | 176 | [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, |
| 175 | INVALID_REG_ADDR, /* TTES - NA */ | 177 | [BQ27XXX_REG_NAC] = 0x0c, |
| 176 | INVALID_REG_ADDR, /* TTECP - NA */ | 178 | [BQ27XXX_REG_FCC] = 0x12, |
| 177 | 0x0c, /* NAC */ | 179 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 178 | 0x12, /* LMD(FCC) */ | 180 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 179 | 0x2a, /* CYCT */ | 181 | [BQ27XXX_REG_SOC] = 0x2c, |
| 180 | INVALID_REG_ADDR, /* AE - NA */ | 182 | [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, |
| 181 | 0x2c, /* SOC(RSOC) */ | 183 | [BQ27XXX_REG_AP] = 0x24, |
| 182 | INVALID_REG_ADDR, /* DCAP - NA */ | 184 | }, |
| 183 | 0x24, /* AP */ | 185 | [BQ27541] = { |
| 184 | }; | 186 | [BQ27XXX_REG_CTRL] = 0x00, |
| 185 | 187 | [BQ27XXX_REG_TEMP] = 0x06, | |
| 186 | static u8 bq27541_regs[] = { | 188 | [BQ27XXX_REG_INT_TEMP] = 0x28, |
| 187 | 0x00, /* CONTROL */ | 189 | [BQ27XXX_REG_VOLT] = 0x08, |
| 188 | 0x06, /* TEMP */ | 190 | [BQ27XXX_REG_AI] = 0x14, |
| 189 | 0x28, /* INT TEMP */ | 191 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 190 | 0x08, /* VOLT */ | 192 | [BQ27XXX_REG_TTE] = 0x16, |
| 191 | 0x14, /* AVG CURR */ | 193 | [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, |
| 192 | 0x0a, /* FLAGS */ | 194 | [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, |
| 193 | 0x16, /* TTE */ | 195 | [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, |
| 194 | INVALID_REG_ADDR, /* TTF - NA */ | 196 | [BQ27XXX_REG_NAC] = 0x0c, |
| 195 | INVALID_REG_ADDR, /* TTES - NA */ | 197 | [BQ27XXX_REG_FCC] = 0x12, |
| 196 | INVALID_REG_ADDR, /* TTECP - NA */ | 198 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 197 | 0x0c, /* NAC */ | 199 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 198 | 0x12, /* LMD(FCC) */ | 200 | [BQ27XXX_REG_SOC] = 0x2c, |
| 199 | 0x2a, /* CYCT */ | 201 | [BQ27XXX_REG_DCAP] = 0x3c, |
| 200 | INVALID_REG_ADDR, /* AE - NA */ | 202 | [BQ27XXX_REG_AP] = 0x24, |
| 201 | 0x2c, /* SOC(RSOC) */ | 203 | }, |
| 202 | 0x3c, /* DCAP */ | 204 | [BQ27545] = { |
| 203 | 0x24, /* AP */ | 205 | [BQ27XXX_REG_CTRL] = 0x00, |
| 204 | }; | 206 | [BQ27XXX_REG_TEMP] = 0x06, |
| 205 | 207 | [BQ27XXX_REG_INT_TEMP] = 0x28, | |
| 206 | static u8 bq27545_regs[] = { | 208 | [BQ27XXX_REG_VOLT] = 0x08, |
| 207 | 0x00, /* CONTROL */ | 209 | [BQ27XXX_REG_AI] = 0x14, |
| 208 | 0x06, /* TEMP */ | 210 | [BQ27XXX_REG_FLAGS] = 0x0a, |
| 209 | 0x28, /* INT TEMP */ | 211 | [BQ27XXX_REG_TTE] = 0x16, |
| 210 | 0x08, /* VOLT */ | 212 | [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, |
| 211 | 0x14, /* AVG CURR */ | 213 | [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, |
| 212 | 0x0a, /* FLAGS */ | 214 | [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, |
| 213 | 0x16, /* TTE */ | 215 | [BQ27XXX_REG_NAC] = 0x0c, |
| 214 | INVALID_REG_ADDR, /* TTF - NA */ | 216 | [BQ27XXX_REG_FCC] = 0x12, |
| 215 | INVALID_REG_ADDR, /* TTES - NA */ | 217 | [BQ27XXX_REG_CYCT] = 0x2a, |
| 216 | INVALID_REG_ADDR, /* TTECP - NA */ | 218 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 217 | 0x0c, /* NAC */ | 219 | [BQ27XXX_REG_SOC] = 0x2c, |
| 218 | 0x12, /* LMD(FCC) */ | 220 | [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, |
| 219 | 0x2a, /* CYCT */ | 221 | [BQ27XXX_REG_AP] = 0x24, |
| 220 | INVALID_REG_ADDR, /* AE - NA */ | 222 | }, |
| 221 | 0x2c, /* SOC(RSOC) */ | 223 | [BQ27421] = { |
| 222 | INVALID_REG_ADDR, /* DCAP - NA */ | 224 | [BQ27XXX_REG_CTRL] = 0x00, |
| 223 | 0x24, /* AP */ | 225 | [BQ27XXX_REG_TEMP] = 0x02, |
| 224 | }; | 226 | [BQ27XXX_REG_INT_TEMP] = 0x1e, |
| 225 | 227 | [BQ27XXX_REG_VOLT] = 0x04, | |
| 226 | static u8 bq27421_regs[] = { | 228 | [BQ27XXX_REG_AI] = 0x10, |
| 227 | 0x00, /* CONTROL */ | 229 | [BQ27XXX_REG_FLAGS] = 0x06, |
| 228 | 0x02, /* TEMP */ | 230 | [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, |
| 229 | 0x1e, /* INT TEMP */ | 231 | [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, |
| 230 | 0x04, /* VOLT */ | 232 | [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, |
| 231 | 0x10, /* AVG CURR */ | 233 | [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, |
| 232 | 0x06, /* FLAGS */ | 234 | [BQ27XXX_REG_NAC] = 0x08, |
| 233 | INVALID_REG_ADDR, /* TTE - NA */ | 235 | [BQ27XXX_REG_FCC] = 0x0e, |
| 234 | INVALID_REG_ADDR, /* TTF - NA */ | 236 | [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, |
| 235 | INVALID_REG_ADDR, /* TTES - NA */ | 237 | [BQ27XXX_REG_AE] = INVALID_REG_ADDR, |
| 236 | INVALID_REG_ADDR, /* TTECP - NA */ | 238 | [BQ27XXX_REG_SOC] = 0x1c, |
| 237 | 0x08, /* NAC */ | 239 | [BQ27XXX_REG_DCAP] = 0x3c, |
| 238 | 0x0e, /* FCC */ | 240 | [BQ27XXX_REG_AP] = 0x18, |
| 239 | INVALID_REG_ADDR, /* CYCT - NA */ | 241 | }, |
| 240 | INVALID_REG_ADDR, /* AE - NA */ | ||
| 241 | 0x1c, /* SOC */ | ||
| 242 | 0x3c, /* DCAP */ | ||
| 243 | 0x18, /* AP */ | ||
| 244 | }; | ||
| 245 | |||
| 246 | static u8 *bq27xxx_regs[] = { | ||
| 247 | [BQ27000] = bq27000_regs, | ||
| 248 | [BQ27010] = bq27010_regs, | ||
| 249 | [BQ27500] = bq27500_regs, | ||
| 250 | [BQ27530] = bq27530_regs, | ||
| 251 | [BQ27541] = bq27541_regs, | ||
| 252 | [BQ27545] = bq27545_regs, | ||
| 253 | [BQ27421] = bq27421_regs, | ||
| 254 | }; | 242 | }; |
| 255 | 243 | ||
| 256 | static enum power_supply_property bq27000_battery_props[] = { | 244 | static enum power_supply_property bq27000_battery_props[] = { |
diff --git a/drivers/power/bq27xxx_battery_i2c.c b/drivers/power/bq27xxx_battery_i2c.c index b8f8d3ade31b..85d4ea2a9c20 100644 --- a/drivers/power/bq27xxx_battery_i2c.c +++ b/drivers/power/bq27xxx_battery_i2c.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * SCI Reset driver for Keystone based devices | 2 | * BQ27xxx battery monitor I2C driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ |
| 5 | * Andrew F. Davis <afd@ti.com> | 5 | * Andrew F. Davis <afd@ti.com> |
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 17876caf31e5..fdc73d686153 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c | |||
| @@ -23,13 +23,16 @@ | |||
| 23 | #include <linux/gpio.h> | 23 | #include <linux/gpio.h> |
| 24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
| 25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/of.h> | ||
| 27 | #include <linux/of_device.h> | ||
| 28 | #include <linux/of_gpio.h> | ||
| 26 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 27 | #include <linux/power_supply.h> | 30 | #include <linux/power_supply.h> |
| 28 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| 29 | #include <linux/power/max8903_charger.h> | 32 | #include <linux/power/max8903_charger.h> |
| 30 | 33 | ||
| 31 | struct max8903_data { | 34 | struct max8903_data { |
| 32 | struct max8903_pdata pdata; | 35 | struct max8903_pdata *pdata; |
| 33 | struct device *dev; | 36 | struct device *dev; |
| 34 | struct power_supply *psy; | 37 | struct power_supply *psy; |
| 35 | struct power_supply_desc psy_desc; | 38 | struct power_supply_desc psy_desc; |
| @@ -53,8 +56,8 @@ static int max8903_get_property(struct power_supply *psy, | |||
| 53 | switch (psp) { | 56 | switch (psp) { |
| 54 | case POWER_SUPPLY_PROP_STATUS: | 57 | case POWER_SUPPLY_PROP_STATUS: |
| 55 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | 58 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; |
| 56 | if (data->pdata.chg) { | 59 | if (gpio_is_valid(data->pdata->chg)) { |
| 57 | if (gpio_get_value(data->pdata.chg) == 0) | 60 | if (gpio_get_value(data->pdata->chg) == 0) |
| 58 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | 61 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
| 59 | else if (data->usb_in || data->ta_in) | 62 | else if (data->usb_in || data->ta_in) |
| 60 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | 63 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; |
| @@ -75,13 +78,14 @@ static int max8903_get_property(struct power_supply *psy, | |||
| 75 | default: | 78 | default: |
| 76 | return -EINVAL; | 79 | return -EINVAL; |
| 77 | } | 80 | } |
| 81 | |||
| 78 | return 0; | 82 | return 0; |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | static irqreturn_t max8903_dcin(int irq, void *_data) | 85 | static irqreturn_t max8903_dcin(int irq, void *_data) |
| 82 | { | 86 | { |
| 83 | struct max8903_data *data = _data; | 87 | struct max8903_data *data = _data; |
| 84 | struct max8903_pdata *pdata = &data->pdata; | 88 | struct max8903_pdata *pdata = data->pdata; |
| 85 | bool ta_in; | 89 | bool ta_in; |
| 86 | enum power_supply_type old_type; | 90 | enum power_supply_type old_type; |
| 87 | 91 | ||
| @@ -93,11 +97,11 @@ static irqreturn_t max8903_dcin(int irq, void *_data) | |||
| 93 | data->ta_in = ta_in; | 97 | data->ta_in = ta_in; |
| 94 | 98 | ||
| 95 | /* Set Current-Limit-Mode 1:DC 0:USB */ | 99 | /* Set Current-Limit-Mode 1:DC 0:USB */ |
| 96 | if (pdata->dcm) | 100 | if (gpio_is_valid(pdata->dcm)) |
| 97 | gpio_set_value(pdata->dcm, ta_in ? 1 : 0); | 101 | gpio_set_value(pdata->dcm, ta_in ? 1 : 0); |
| 98 | 102 | ||
| 99 | /* Charger Enable / Disable (cen is negated) */ | 103 | /* Charger Enable / Disable (cen is negated) */ |
| 100 | if (pdata->cen) | 104 | if (gpio_is_valid(pdata->cen)) |
| 101 | gpio_set_value(pdata->cen, ta_in ? 0 : | 105 | gpio_set_value(pdata->cen, ta_in ? 0 : |
| 102 | (data->usb_in ? 0 : 1)); | 106 | (data->usb_in ? 0 : 1)); |
| 103 | 107 | ||
| @@ -122,7 +126,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data) | |||
| 122 | static irqreturn_t max8903_usbin(int irq, void *_data) | 126 | static irqreturn_t max8903_usbin(int irq, void *_data) |
| 123 | { | 127 | { |
| 124 | struct max8903_data *data = _data; | 128 | struct max8903_data *data = _data; |
| 125 | struct max8903_pdata *pdata = &data->pdata; | 129 | struct max8903_pdata *pdata = data->pdata; |
| 126 | bool usb_in; | 130 | bool usb_in; |
| 127 | enum power_supply_type old_type; | 131 | enum power_supply_type old_type; |
| 128 | 132 | ||
| @@ -136,7 +140,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data) | |||
| 136 | /* Do not touch Current-Limit-Mode */ | 140 | /* Do not touch Current-Limit-Mode */ |
| 137 | 141 | ||
| 138 | /* Charger Enable / Disable (cen is negated) */ | 142 | /* Charger Enable / Disable (cen is negated) */ |
| 139 | if (pdata->cen) | 143 | if (gpio_is_valid(pdata->cen)) |
| 140 | gpio_set_value(pdata->cen, usb_in ? 0 : | 144 | gpio_set_value(pdata->cen, usb_in ? 0 : |
| 141 | (data->ta_in ? 0 : 1)); | 145 | (data->ta_in ? 0 : 1)); |
| 142 | 146 | ||
| @@ -161,7 +165,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data) | |||
| 161 | static irqreturn_t max8903_fault(int irq, void *_data) | 165 | static irqreturn_t max8903_fault(int irq, void *_data) |
| 162 | { | 166 | { |
| 163 | struct max8903_data *data = _data; | 167 | struct max8903_data *data = _data; |
| 164 | struct max8903_pdata *pdata = &data->pdata; | 168 | struct max8903_pdata *pdata = data->pdata; |
| 165 | bool fault; | 169 | bool fault; |
| 166 | 170 | ||
| 167 | fault = gpio_get_value(pdata->flt) ? false : true; | 171 | fault = gpio_get_value(pdata->flt) ? false : true; |
| @@ -179,57 +183,109 @@ static irqreturn_t max8903_fault(int irq, void *_data) | |||
| 179 | return IRQ_HANDLED; | 183 | return IRQ_HANDLED; |
| 180 | } | 184 | } |
| 181 | 185 | ||
| 182 | static int max8903_probe(struct platform_device *pdev) | 186 | static struct max8903_pdata *max8903_parse_dt_data(struct device *dev) |
| 183 | { | 187 | { |
| 184 | struct max8903_data *data; | 188 | struct device_node *np = dev->of_node; |
| 189 | struct max8903_pdata *pdata = NULL; | ||
| 190 | |||
| 191 | if (!np) | ||
| 192 | return NULL; | ||
| 193 | |||
| 194 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
| 195 | if (!pdata) | ||
| 196 | return NULL; | ||
| 197 | |||
| 198 | pdata->dc_valid = false; | ||
| 199 | pdata->usb_valid = false; | ||
| 200 | |||
| 201 | pdata->cen = of_get_named_gpio(np, "cen-gpios", 0); | ||
| 202 | if (!gpio_is_valid(pdata->cen)) | ||
| 203 | pdata->cen = -EINVAL; | ||
| 204 | |||
| 205 | pdata->chg = of_get_named_gpio(np, "chg-gpios", 0); | ||
| 206 | if (!gpio_is_valid(pdata->chg)) | ||
| 207 | pdata->chg = -EINVAL; | ||
| 208 | |||
| 209 | pdata->flt = of_get_named_gpio(np, "flt-gpios", 0); | ||
| 210 | if (!gpio_is_valid(pdata->flt)) | ||
| 211 | pdata->flt = -EINVAL; | ||
| 212 | |||
| 213 | pdata->usus = of_get_named_gpio(np, "usus-gpios", 0); | ||
| 214 | if (!gpio_is_valid(pdata->usus)) | ||
| 215 | pdata->usus = -EINVAL; | ||
| 216 | |||
| 217 | pdata->dcm = of_get_named_gpio(np, "dcm-gpios", 0); | ||
| 218 | if (!gpio_is_valid(pdata->dcm)) | ||
| 219 | pdata->dcm = -EINVAL; | ||
| 220 | |||
| 221 | pdata->dok = of_get_named_gpio(np, "dok-gpios", 0); | ||
| 222 | if (!gpio_is_valid(pdata->dok)) | ||
| 223 | pdata->dok = -EINVAL; | ||
| 224 | else | ||
| 225 | pdata->dc_valid = true; | ||
| 226 | |||
| 227 | pdata->uok = of_get_named_gpio(np, "uok-gpios", 0); | ||
| 228 | if (!gpio_is_valid(pdata->uok)) | ||
| 229 | pdata->uok = -EINVAL; | ||
| 230 | else | ||
| 231 | pdata->usb_valid = true; | ||
| 232 | |||
| 233 | return pdata; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int max8903_setup_gpios(struct platform_device *pdev) | ||
| 237 | { | ||
| 238 | struct max8903_data *data = platform_get_drvdata(pdev); | ||
| 185 | struct device *dev = &pdev->dev; | 239 | struct device *dev = &pdev->dev; |
| 186 | struct max8903_pdata *pdata = pdev->dev.platform_data; | 240 | struct max8903_pdata *pdata = pdev->dev.platform_data; |
| 187 | struct power_supply_config psy_cfg = {}; | ||
| 188 | int ret = 0; | 241 | int ret = 0; |
| 189 | int gpio; | 242 | int gpio; |
| 190 | int ta_in = 0; | 243 | int ta_in = 0; |
| 191 | int usb_in = 0; | 244 | int usb_in = 0; |
| 192 | 245 | ||
| 193 | data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); | ||
| 194 | if (data == NULL) { | ||
| 195 | dev_err(dev, "Cannot allocate memory.\n"); | ||
| 196 | return -ENOMEM; | ||
| 197 | } | ||
| 198 | memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata)); | ||
| 199 | data->dev = dev; | ||
| 200 | platform_set_drvdata(pdev, data); | ||
| 201 | |||
| 202 | if (pdata->dc_valid == false && pdata->usb_valid == false) { | ||
| 203 | dev_err(dev, "No valid power sources.\n"); | ||
| 204 | return -EINVAL; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (pdata->dc_valid) { | 246 | if (pdata->dc_valid) { |
| 208 | if (pdata->dok && gpio_is_valid(pdata->dok) && | 247 | if (gpio_is_valid(pdata->dok)) { |
| 209 | pdata->dcm && gpio_is_valid(pdata->dcm)) { | 248 | ret = devm_gpio_request(dev, pdata->dok, |
| 249 | data->psy_desc.name); | ||
| 250 | if (ret) { | ||
| 251 | dev_err(dev, | ||
| 252 | "Failed GPIO request for dok: %d err %d\n", | ||
| 253 | pdata->dok, ret); | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 210 | gpio = pdata->dok; /* PULL_UPed Interrupt */ | 257 | gpio = pdata->dok; /* PULL_UPed Interrupt */ |
| 211 | ta_in = gpio_get_value(gpio) ? 0 : 1; | 258 | ta_in = gpio_get_value(gpio) ? 0 : 1; |
| 212 | |||
| 213 | gpio = pdata->dcm; /* Output */ | ||
| 214 | gpio_set_value(gpio, ta_in); | ||
| 215 | } else { | 259 | } else { |
| 216 | dev_err(dev, "When DC is wired, DOK and DCM should" | 260 | dev_err(dev, "When DC is wired, DOK should be wired as well.\n"); |
| 217 | " be wired as well.\n"); | ||
| 218 | return -EINVAL; | 261 | return -EINVAL; |
| 219 | } | 262 | } |
| 220 | } else { | 263 | } |
| 221 | if (pdata->dcm) { | 264 | |
| 222 | if (gpio_is_valid(pdata->dcm)) | 265 | if (gpio_is_valid(pdata->dcm)) { |
| 223 | gpio_set_value(pdata->dcm, 0); | 266 | ret = devm_gpio_request(dev, pdata->dcm, data->psy_desc.name); |
| 224 | else { | 267 | if (ret) { |
| 225 | dev_err(dev, "Invalid pin: dcm.\n"); | 268 | dev_err(dev, |
| 226 | return -EINVAL; | 269 | "Failed GPIO request for dcm: %d err %d\n", |
| 227 | } | 270 | pdata->dcm, ret); |
| 271 | return ret; | ||
| 228 | } | 272 | } |
| 273 | |||
| 274 | gpio = pdata->dcm; /* Output */ | ||
| 275 | gpio_set_value(gpio, ta_in); | ||
| 229 | } | 276 | } |
| 230 | 277 | ||
| 231 | if (pdata->usb_valid) { | 278 | if (pdata->usb_valid) { |
| 232 | if (pdata->uok && gpio_is_valid(pdata->uok)) { | 279 | if (gpio_is_valid(pdata->uok)) { |
| 280 | ret = devm_gpio_request(dev, pdata->uok, | ||
| 281 | data->psy_desc.name); | ||
| 282 | if (ret) { | ||
| 283 | dev_err(dev, | ||
| 284 | "Failed GPIO request for uok: %d err %d\n", | ||
| 285 | pdata->uok, ret); | ||
| 286 | return ret; | ||
| 287 | } | ||
| 288 | |||
| 233 | gpio = pdata->uok; | 289 | gpio = pdata->uok; |
| 234 | usb_in = gpio_get_value(gpio) ? 0 : 1; | 290 | usb_in = gpio_get_value(gpio) ? 0 : 1; |
| 235 | } else { | 291 | } else { |
| @@ -239,33 +295,45 @@ static int max8903_probe(struct platform_device *pdev) | |||
| 239 | } | 295 | } |
| 240 | } | 296 | } |
| 241 | 297 | ||
| 242 | if (pdata->cen) { | 298 | if (gpio_is_valid(pdata->cen)) { |
| 243 | if (gpio_is_valid(pdata->cen)) { | 299 | ret = devm_gpio_request(dev, pdata->cen, data->psy_desc.name); |
| 244 | gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); | 300 | if (ret) { |
| 245 | } else { | 301 | dev_err(dev, |
| 246 | dev_err(dev, "Invalid pin: cen.\n"); | 302 | "Failed GPIO request for cen: %d err %d\n", |
| 247 | return -EINVAL; | 303 | pdata->cen, ret); |
| 304 | return ret; | ||
| 248 | } | 305 | } |
| 306 | |||
| 307 | gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); | ||
| 249 | } | 308 | } |
| 250 | 309 | ||
| 251 | if (pdata->chg) { | 310 | if (gpio_is_valid(pdata->chg)) { |
| 252 | if (!gpio_is_valid(pdata->chg)) { | 311 | ret = devm_gpio_request(dev, pdata->chg, data->psy_desc.name); |
| 253 | dev_err(dev, "Invalid pin: chg.\n"); | 312 | if (ret) { |
| 254 | return -EINVAL; | 313 | dev_err(dev, |
| 314 | "Failed GPIO request for chg: %d err %d\n", | ||
| 315 | pdata->chg, ret); | ||
| 316 | return ret; | ||
| 255 | } | 317 | } |
| 256 | } | 318 | } |
| 257 | 319 | ||
| 258 | if (pdata->flt) { | 320 | if (gpio_is_valid(pdata->flt)) { |
| 259 | if (!gpio_is_valid(pdata->flt)) { | 321 | ret = devm_gpio_request(dev, pdata->flt, data->psy_desc.name); |
| 260 | dev_err(dev, "Invalid pin: flt.\n"); | 322 | if (ret) { |
| 261 | return -EINVAL; | 323 | dev_err(dev, |
| 324 | "Failed GPIO request for flt: %d err %d\n", | ||
| 325 | pdata->flt, ret); | ||
| 326 | return ret; | ||
| 262 | } | 327 | } |
| 263 | } | 328 | } |
| 264 | 329 | ||
| 265 | if (pdata->usus) { | 330 | if (gpio_is_valid(pdata->usus)) { |
| 266 | if (!gpio_is_valid(pdata->usus)) { | 331 | ret = devm_gpio_request(dev, pdata->usus, data->psy_desc.name); |
| 267 | dev_err(dev, "Invalid pin: usus.\n"); | 332 | if (ret) { |
| 268 | return -EINVAL; | 333 | dev_err(dev, |
| 334 | "Failed GPIO request for usus: %d err %d\n", | ||
| 335 | pdata->usus, ret); | ||
| 336 | return ret; | ||
| 269 | } | 337 | } |
| 270 | } | 338 | } |
| 271 | 339 | ||
| @@ -273,14 +341,52 @@ static int max8903_probe(struct platform_device *pdev) | |||
| 273 | data->ta_in = ta_in; | 341 | data->ta_in = ta_in; |
| 274 | data->usb_in = usb_in; | 342 | data->usb_in = usb_in; |
| 275 | 343 | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int max8903_probe(struct platform_device *pdev) | ||
| 348 | { | ||
| 349 | struct max8903_data *data; | ||
| 350 | struct device *dev = &pdev->dev; | ||
| 351 | struct max8903_pdata *pdata = pdev->dev.platform_data; | ||
| 352 | struct power_supply_config psy_cfg = {}; | ||
| 353 | int ret = 0; | ||
| 354 | |||
| 355 | data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); | ||
| 356 | if (!data) | ||
| 357 | return -ENOMEM; | ||
| 358 | |||
| 359 | if (IS_ENABLED(CONFIG_OF) && !pdata && dev->of_node) | ||
| 360 | pdata = max8903_parse_dt_data(dev); | ||
| 361 | |||
| 362 | if (!pdata) { | ||
| 363 | dev_err(dev, "No platform data.\n"); | ||
| 364 | return -EINVAL; | ||
| 365 | } | ||
| 366 | |||
| 367 | pdev->dev.platform_data = pdata; | ||
| 368 | data->pdata = pdata; | ||
| 369 | data->dev = dev; | ||
| 370 | platform_set_drvdata(pdev, data); | ||
| 371 | |||
| 372 | if (pdata->dc_valid == false && pdata->usb_valid == false) { | ||
| 373 | dev_err(dev, "No valid power sources.\n"); | ||
| 374 | return -EINVAL; | ||
| 375 | } | ||
| 376 | |||
| 377 | ret = max8903_setup_gpios(pdev); | ||
| 378 | if (ret) | ||
| 379 | return ret; | ||
| 380 | |||
| 276 | data->psy_desc.name = "max8903_charger"; | 381 | data->psy_desc.name = "max8903_charger"; |
| 277 | data->psy_desc.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS : | 382 | data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS : |
| 278 | ((usb_in) ? POWER_SUPPLY_TYPE_USB : | 383 | ((data->usb_in) ? POWER_SUPPLY_TYPE_USB : |
| 279 | POWER_SUPPLY_TYPE_BATTERY); | 384 | POWER_SUPPLY_TYPE_BATTERY); |
| 280 | data->psy_desc.get_property = max8903_get_property; | 385 | data->psy_desc.get_property = max8903_get_property; |
| 281 | data->psy_desc.properties = max8903_charger_props; | 386 | data->psy_desc.properties = max8903_charger_props; |
| 282 | data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); | 387 | data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); |
| 283 | 388 | ||
| 389 | psy_cfg.of_node = dev->of_node; | ||
| 284 | psy_cfg.drv_data = data; | 390 | psy_cfg.drv_data = data; |
| 285 | 391 | ||
| 286 | data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); | 392 | data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); |
| @@ -315,7 +421,7 @@ static int max8903_probe(struct platform_device *pdev) | |||
| 315 | } | 421 | } |
| 316 | } | 422 | } |
| 317 | 423 | ||
| 318 | if (pdata->flt) { | 424 | if (gpio_is_valid(pdata->flt)) { |
| 319 | ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt), | 425 | ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt), |
| 320 | NULL, max8903_fault, | 426 | NULL, max8903_fault, |
| 321 | IRQF_TRIGGER_FALLING | | 427 | IRQF_TRIGGER_FALLING | |
| @@ -331,10 +437,17 @@ static int max8903_probe(struct platform_device *pdev) | |||
| 331 | return 0; | 437 | return 0; |
| 332 | } | 438 | } |
| 333 | 439 | ||
| 440 | static const struct of_device_id max8903_match_ids[] = { | ||
| 441 | { .compatible = "maxim,max8903", }, | ||
| 442 | { /* sentinel */ } | ||
| 443 | }; | ||
| 444 | MODULE_DEVICE_TABLE(of, max8903_match_ids); | ||
| 445 | |||
| 334 | static struct platform_driver max8903_driver = { | 446 | static struct platform_driver max8903_driver = { |
| 335 | .probe = max8903_probe, | 447 | .probe = max8903_probe, |
| 336 | .driver = { | 448 | .driver = { |
| 337 | .name = "max8903-charger", | 449 | .name = "max8903-charger", |
| 450 | .of_match_table = max8903_match_ids | ||
| 338 | }, | 451 | }, |
| 339 | }; | 452 | }; |
| 340 | 453 | ||
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index b13cd074c52a..a74d8ca383a1 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
| @@ -491,8 +491,11 @@ int power_supply_get_property(struct power_supply *psy, | |||
| 491 | enum power_supply_property psp, | 491 | enum power_supply_property psp, |
| 492 | union power_supply_propval *val) | 492 | union power_supply_propval *val) |
| 493 | { | 493 | { |
| 494 | if (atomic_read(&psy->use_cnt) <= 0) | 494 | if (atomic_read(&psy->use_cnt) <= 0) { |
| 495 | if (!psy->initialized) | ||
| 496 | return -EAGAIN; | ||
| 495 | return -ENODEV; | 497 | return -ENODEV; |
| 498 | } | ||
| 496 | 499 | ||
| 497 | return psy->desc->get_property(psy, psp, val); | 500 | return psy->desc->get_property(psy, psp, val); |
| 498 | } | 501 | } |
| @@ -785,6 +788,7 @@ __power_supply_register(struct device *parent, | |||
| 785 | * after calling power_supply_register()). | 788 | * after calling power_supply_register()). |
| 786 | */ | 789 | */ |
| 787 | atomic_inc(&psy->use_cnt); | 790 | atomic_inc(&psy->use_cnt); |
| 791 | psy->initialized = true; | ||
| 788 | 792 | ||
| 789 | queue_delayed_work(system_power_efficient_wq, | 793 | queue_delayed_work(system_power_efficient_wq, |
| 790 | &psy->deferred_register_work, | 794 | &psy->deferred_register_work, |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 80fed98832f9..bcde8d13476a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
| @@ -83,7 +83,7 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
| 83 | if (ret == -ENODATA) | 83 | if (ret == -ENODATA) |
| 84 | dev_dbg(dev, "driver has no data for `%s' property\n", | 84 | dev_dbg(dev, "driver has no data for `%s' property\n", |
| 85 | attr->attr.name); | 85 | attr->attr.name); |
| 86 | else if (ret != -ENODEV) | 86 | else if (ret != -ENODEV && ret != -EAGAIN) |
| 87 | dev_err(dev, "driver failed to report `%s' property: %zd\n", | 87 | dev_err(dev, "driver failed to report `%s' property: %zd\n", |
| 88 | attr->attr.name, ret); | 88 | attr->attr.name, ret); |
| 89 | return ret; | 89 | return ret; |
diff --git a/drivers/power/qcom_smbb.c b/drivers/power/qcom_smbb.c index 5eb1e9e543e2..b5896ba2a602 100644 --- a/drivers/power/qcom_smbb.c +++ b/drivers/power/qcom_smbb.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/power_supply.h> | 34 | #include <linux/power_supply.h> |
| 35 | #include <linux/regmap.h> | 35 | #include <linux/regmap.h> |
| 36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
| 37 | #include <linux/extcon.h> | ||
| 37 | 38 | ||
| 38 | #define SMBB_CHG_VMAX 0x040 | 39 | #define SMBB_CHG_VMAX 0x040 |
| 39 | #define SMBB_CHG_VSAFE 0x041 | 40 | #define SMBB_CHG_VSAFE 0x041 |
| @@ -111,6 +112,7 @@ struct smbb_charger { | |||
| 111 | unsigned int revision; | 112 | unsigned int revision; |
| 112 | unsigned int addr; | 113 | unsigned int addr; |
| 113 | struct device *dev; | 114 | struct device *dev; |
| 115 | struct extcon_dev *edev; | ||
| 114 | 116 | ||
| 115 | bool dc_disabled; | 117 | bool dc_disabled; |
| 116 | bool jeita_ext_temp; | 118 | bool jeita_ext_temp; |
| @@ -125,6 +127,11 @@ struct smbb_charger { | |||
| 125 | struct regmap *regmap; | 127 | struct regmap *regmap; |
| 126 | }; | 128 | }; |
| 127 | 129 | ||
| 130 | static const unsigned int smbb_usb_extcon_cable[] = { | ||
| 131 | EXTCON_USB, | ||
| 132 | EXTCON_NONE, | ||
| 133 | }; | ||
| 134 | |||
| 128 | static int smbb_vbat_weak_fn(unsigned int index) | 135 | static int smbb_vbat_weak_fn(unsigned int index) |
| 129 | { | 136 | { |
| 130 | return 2100000 + index * 100000; | 137 | return 2100000 + index * 100000; |
| @@ -371,6 +378,8 @@ static irqreturn_t smbb_usb_valid_handler(int irq, void *_data) | |||
| 371 | struct smbb_charger *chg = _data; | 378 | struct smbb_charger *chg = _data; |
| 372 | 379 | ||
| 373 | smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); | 380 | smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); |
| 381 | extcon_set_cable_state_(chg->edev, EXTCON_USB, | ||
| 382 | chg->status & STATUS_USBIN_VALID); | ||
| 374 | power_supply_changed(chg->usb_psy); | 383 | power_supply_changed(chg->usb_psy); |
| 375 | 384 | ||
| 376 | return IRQ_HANDLED; | 385 | return IRQ_HANDLED; |
| @@ -849,6 +858,18 @@ static int smbb_charger_probe(struct platform_device *pdev) | |||
| 849 | return PTR_ERR(chg->usb_psy); | 858 | return PTR_ERR(chg->usb_psy); |
| 850 | } | 859 | } |
| 851 | 860 | ||
| 861 | chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable); | ||
| 862 | if (IS_ERR(chg->edev)) { | ||
| 863 | dev_err(&pdev->dev, "failed to allocate extcon device\n"); | ||
| 864 | return -ENOMEM; | ||
| 865 | } | ||
| 866 | |||
| 867 | rc = devm_extcon_dev_register(&pdev->dev, chg->edev); | ||
| 868 | if (rc < 0) { | ||
| 869 | dev_err(&pdev->dev, "failed to register extcon device\n"); | ||
| 870 | return rc; | ||
| 871 | } | ||
| 872 | |||
| 852 | if (!chg->dc_disabled) { | 873 | if (!chg->dc_disabled) { |
| 853 | dc_cfg.drv_data = chg; | 874 | dc_cfg.drv_data = chg; |
| 854 | dc_cfg.supplied_to = smbb_bif; | 875 | dc_cfg.supplied_to = smbb_bif; |
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 9bb2622c23bf..7053abced0bc 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
| @@ -148,7 +148,8 @@ config POWER_RESET_XGENE | |||
| 148 | 148 | ||
| 149 | config POWER_RESET_KEYSTONE | 149 | config POWER_RESET_KEYSTONE |
| 150 | bool "Keystone reset driver" | 150 | bool "Keystone reset driver" |
| 151 | depends on ARCH_KEYSTONE | 151 | depends on ARCH_KEYSTONE || COMPILE_TEST |
| 152 | depends on HAS_IOMEM | ||
| 152 | select MFD_SYSCON | 153 | select MFD_SYSCON |
| 153 | help | 154 | help |
| 154 | Reboot support for the KEYSTONE SoCs. | 155 | Reboot support for the KEYSTONE SoCs. |
| @@ -183,5 +184,19 @@ config POWER_RESET_ZX | |||
| 183 | help | 184 | help |
| 184 | Reboot support for ZTE SoCs. | 185 | Reboot support for ZTE SoCs. |
| 185 | 186 | ||
| 187 | config REBOOT_MODE | ||
| 188 | tristate | ||
| 189 | |||
| 190 | config SYSCON_REBOOT_MODE | ||
| 191 | tristate "Generic SYSCON regmap reboot mode driver" | ||
| 192 | depends on OF | ||
| 193 | select REBOOT_MODE | ||
| 194 | select MFD_SYSCON | ||
| 195 | help | ||
| 196 | Say y here will enable reboot mode driver. This will | ||
| 197 | get reboot mode arguments and store it in SYSCON mapped | ||
| 198 | register, then the bootloader can read it to take different | ||
| 199 | action according to the mode. | ||
| 200 | |||
| 186 | endif | 201 | endif |
| 187 | 202 | ||
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index ab7aa8614d1f..d6b2560d5c4a 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
| @@ -21,3 +21,5 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o | |||
| 21 | obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o | 21 | obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o |
| 22 | obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o | 22 | obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o |
| 23 | obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o | 23 | obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o |
| 24 | obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o | ||
| 25 | obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o | ||
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c new file mode 100644 index 000000000000..2dfbbce0f817 --- /dev/null +++ b/drivers/power/reset/reboot-mode.c | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/of.h> | ||
| 15 | #include <linux/reboot.h> | ||
| 16 | #include "reboot-mode.h" | ||
| 17 | |||
| 18 | #define PREFIX "mode-" | ||
| 19 | |||
| 20 | struct mode_info { | ||
| 21 | const char *mode; | ||
| 22 | u32 magic; | ||
| 23 | struct list_head list; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, | ||
| 27 | const char *cmd) | ||
| 28 | { | ||
| 29 | const char *normal = "normal"; | ||
| 30 | int magic = 0; | ||
| 31 | struct mode_info *info; | ||
| 32 | |||
| 33 | if (!cmd) | ||
| 34 | cmd = normal; | ||
| 35 | |||
| 36 | list_for_each_entry(info, &reboot->head, list) { | ||
| 37 | if (!strcmp(info->mode, cmd)) { | ||
| 38 | magic = info->magic; | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | return magic; | ||
| 44 | } | ||
| 45 | |||
| 46 | static int reboot_mode_notify(struct notifier_block *this, | ||
| 47 | unsigned long mode, void *cmd) | ||
| 48 | { | ||
| 49 | struct reboot_mode_driver *reboot; | ||
| 50 | unsigned int magic; | ||
| 51 | |||
| 52 | reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); | ||
| 53 | magic = get_reboot_mode_magic(reboot, cmd); | ||
| 54 | if (magic) | ||
| 55 | reboot->write(reboot, magic); | ||
| 56 | |||
| 57 | return NOTIFY_DONE; | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * reboot_mode_register - register a reboot mode driver | ||
| 62 | * @reboot: reboot mode driver | ||
| 63 | * | ||
| 64 | * Returns: 0 on success or a negative error code on failure. | ||
| 65 | */ | ||
| 66 | int reboot_mode_register(struct reboot_mode_driver *reboot) | ||
| 67 | { | ||
| 68 | struct mode_info *info; | ||
| 69 | struct property *prop; | ||
| 70 | struct device_node *np = reboot->dev->of_node; | ||
| 71 | size_t len = strlen(PREFIX); | ||
| 72 | int ret; | ||
| 73 | |||
| 74 | INIT_LIST_HEAD(&reboot->head); | ||
| 75 | |||
| 76 | for_each_property_of_node(np, prop) { | ||
| 77 | if (strncmp(prop->name, PREFIX, len)) | ||
| 78 | continue; | ||
| 79 | |||
| 80 | info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL); | ||
| 81 | if (!info) { | ||
| 82 | ret = -ENOMEM; | ||
| 83 | goto error; | ||
| 84 | } | ||
| 85 | |||
| 86 | if (of_property_read_u32(np, prop->name, &info->magic)) { | ||
| 87 | dev_err(reboot->dev, "reboot mode %s without magic number\n", | ||
| 88 | info->mode); | ||
| 89 | devm_kfree(reboot->dev, info); | ||
| 90 | continue; | ||
| 91 | } | ||
| 92 | |||
| 93 | info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); | ||
| 94 | if (!info->mode) { | ||
| 95 | ret = -ENOMEM; | ||
| 96 | goto error; | ||
| 97 | } else if (info->mode[0] == '\0') { | ||
| 98 | kfree_const(info->mode); | ||
| 99 | ret = -EINVAL; | ||
| 100 | dev_err(reboot->dev, "invalid mode name(%s): too short!\n", | ||
| 101 | prop->name); | ||
| 102 | goto error; | ||
| 103 | } | ||
| 104 | |||
| 105 | list_add_tail(&info->list, &reboot->head); | ||
| 106 | } | ||
| 107 | |||
| 108 | reboot->reboot_notifier.notifier_call = reboot_mode_notify; | ||
| 109 | register_reboot_notifier(&reboot->reboot_notifier); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | |||
| 113 | error: | ||
| 114 | list_for_each_entry(info, &reboot->head, list) | ||
| 115 | kfree_const(info->mode); | ||
| 116 | |||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | EXPORT_SYMBOL_GPL(reboot_mode_register); | ||
| 120 | |||
| 121 | /** | ||
| 122 | * reboot_mode_unregister - unregister a reboot mode driver | ||
| 123 | * @reboot: reboot mode driver | ||
| 124 | */ | ||
| 125 | int reboot_mode_unregister(struct reboot_mode_driver *reboot) | ||
| 126 | { | ||
| 127 | struct mode_info *info; | ||
| 128 | |||
| 129 | unregister_reboot_notifier(&reboot->reboot_notifier); | ||
| 130 | |||
| 131 | list_for_each_entry(info, &reboot->head, list) | ||
| 132 | kfree_const(info->mode); | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | EXPORT_SYMBOL_GPL(reboot_mode_unregister); | ||
| 137 | |||
| 138 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com"); | ||
| 139 | MODULE_DESCRIPTION("System reboot mode core library"); | ||
| 140 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/power/reset/reboot-mode.h b/drivers/power/reset/reboot-mode.h new file mode 100644 index 000000000000..2491bb71f591 --- /dev/null +++ b/drivers/power/reset/reboot-mode.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef __REBOOT_MODE_H__ | ||
| 2 | #define __REBOOT_MODE_H__ | ||
| 3 | |||
| 4 | struct reboot_mode_driver { | ||
| 5 | struct device *dev; | ||
| 6 | struct list_head head; | ||
| 7 | int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); | ||
| 8 | struct notifier_block reboot_notifier; | ||
| 9 | }; | ||
| 10 | |||
| 11 | int reboot_mode_register(struct reboot_mode_driver *reboot); | ||
| 12 | int reboot_mode_unregister(struct reboot_mode_driver *reboot); | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 5560b0dbc180..b68338399e5e 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c | |||
| @@ -30,7 +30,7 @@ static struct regmap *map; | |||
| 30 | static u32 offset; | 30 | static u32 offset; |
| 31 | static u32 mask; | 31 | static u32 mask; |
| 32 | 32 | ||
| 33 | void syscon_poweroff(void) | 33 | static void syscon_poweroff(void) |
| 34 | { | 34 | { |
| 35 | /* Issue the poweroff */ | 35 | /* Issue the poweroff */ |
| 36 | regmap_write(map, offset, mask); | 36 | regmap_write(map, offset, mask); |
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c new file mode 100644 index 000000000000..9e1cba5dd58e --- /dev/null +++ b/drivers/power/reset/syscon-reboot-mode.c | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/of.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/reboot.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | #include <linux/mfd/syscon.h> | ||
| 18 | #include "reboot-mode.h" | ||
| 19 | |||
| 20 | struct syscon_reboot_mode { | ||
| 21 | struct regmap *map; | ||
| 22 | struct reboot_mode_driver reboot; | ||
| 23 | u32 offset; | ||
| 24 | u32 mask; | ||
| 25 | }; | ||
| 26 | |||
| 27 | static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot, | ||
| 28 | unsigned int magic) | ||
| 29 | { | ||
| 30 | struct syscon_reboot_mode *syscon_rbm; | ||
| 31 | int ret; | ||
| 32 | |||
| 33 | syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot); | ||
| 34 | |||
| 35 | ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset, | ||
| 36 | syscon_rbm->mask, magic); | ||
| 37 | if (ret < 0) | ||
| 38 | dev_err(reboot->dev, "update reboot mode bits failed\n"); | ||
| 39 | |||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | static int syscon_reboot_mode_probe(struct platform_device *pdev) | ||
| 44 | { | ||
| 45 | int ret; | ||
| 46 | struct syscon_reboot_mode *syscon_rbm; | ||
| 47 | |||
| 48 | syscon_rbm = devm_kzalloc(&pdev->dev, sizeof(*syscon_rbm), GFP_KERNEL); | ||
| 49 | if (!syscon_rbm) | ||
| 50 | return -ENOMEM; | ||
| 51 | |||
| 52 | syscon_rbm->reboot.dev = &pdev->dev; | ||
| 53 | syscon_rbm->reboot.write = syscon_reboot_mode_write; | ||
| 54 | syscon_rbm->mask = 0xffffffff; | ||
| 55 | |||
| 56 | dev_set_drvdata(&pdev->dev, syscon_rbm); | ||
| 57 | |||
| 58 | syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node); | ||
| 59 | if (IS_ERR(syscon_rbm->map)) | ||
| 60 | return PTR_ERR(syscon_rbm->map); | ||
| 61 | |||
| 62 | if (of_property_read_u32(pdev->dev.of_node, "offset", | ||
| 63 | &syscon_rbm->offset)) | ||
| 64 | return -EINVAL; | ||
| 65 | |||
| 66 | of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask); | ||
| 67 | |||
| 68 | ret = reboot_mode_register(&syscon_rbm->reboot); | ||
| 69 | if (ret) | ||
| 70 | dev_err(&pdev->dev, "can't register reboot mode\n"); | ||
| 71 | |||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int syscon_reboot_mode_remove(struct platform_device *pdev) | ||
| 76 | { | ||
| 77 | struct syscon_reboot_mode *syscon_rbm = dev_get_drvdata(&pdev->dev); | ||
| 78 | |||
| 79 | return reboot_mode_unregister(&syscon_rbm->reboot); | ||
| 80 | } | ||
| 81 | |||
| 82 | static const struct of_device_id syscon_reboot_mode_of_match[] = { | ||
| 83 | { .compatible = "syscon-reboot-mode" }, | ||
| 84 | {} | ||
| 85 | }; | ||
| 86 | |||
| 87 | static struct platform_driver syscon_reboot_mode_driver = { | ||
| 88 | .probe = syscon_reboot_mode_probe, | ||
| 89 | .remove = syscon_reboot_mode_remove, | ||
| 90 | .driver = { | ||
| 91 | .name = "syscon-reboot-mode", | ||
| 92 | .of_match_table = syscon_reboot_mode_of_match, | ||
| 93 | }, | ||
| 94 | }; | ||
| 95 | module_platform_driver(syscon_reboot_mode_driver); | ||
| 96 | |||
| 97 | MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com"); | ||
| 98 | MODULE_DESCRIPTION("SYSCON reboot mode driver"); | ||
| 99 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/linux/power/max8903_charger.h b/include/linux/power/max8903_charger.h index 24f51db8a83f..89d3f1cb3433 100644 --- a/include/linux/power/max8903_charger.h +++ b/include/linux/power/max8903_charger.h | |||
| @@ -26,8 +26,8 @@ | |||
| 26 | struct max8903_pdata { | 26 | struct max8903_pdata { |
| 27 | /* | 27 | /* |
| 28 | * GPIOs | 28 | * GPIOs |
| 29 | * cen, chg, flt, and usus are optional. | 29 | * cen, chg, flt, dcm and usus are optional. |
| 30 | * dok, dcm, and uok are not optional depending on the status of | 30 | * dok and uok are not optional depending on the status of |
| 31 | * dc_valid and usb_valid. | 31 | * dc_valid and usb_valid. |
| 32 | */ | 32 | */ |
| 33 | int cen; /* Charger Enable input */ | 33 | int cen; /* Charger Enable input */ |
| @@ -41,7 +41,7 @@ struct max8903_pdata { | |||
| 41 | /* | 41 | /* |
| 42 | * DC(Adapter/TA) is wired | 42 | * DC(Adapter/TA) is wired |
| 43 | * When dc_valid is true, | 43 | * When dc_valid is true, |
| 44 | * dok and dcm should be valid. | 44 | * dok should be valid. |
| 45 | * | 45 | * |
| 46 | * At least one of dc_valid or usb_valid should be true. | 46 | * At least one of dc_valid or usb_valid should be true. |
| 47 | */ | 47 | */ |
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 751061790626..3965503315ef 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
| @@ -248,6 +248,7 @@ struct power_supply { | |||
| 248 | struct delayed_work deferred_register_work; | 248 | struct delayed_work deferred_register_work; |
| 249 | spinlock_t changed_lock; | 249 | spinlock_t changed_lock; |
| 250 | bool changed; | 250 | bool changed; |
| 251 | bool initialized; | ||
| 251 | atomic_t use_cnt; | 252 | atomic_t use_cnt; |
| 252 | #ifdef CONFIG_THERMAL | 253 | #ifdef CONFIG_THERMAL |
| 253 | struct thermal_zone_device *tzd; | 254 | struct thermal_zone_device *tzd; |
