diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-26 22:49:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-26 22:49:09 -0400 |
commit | f7816ad0f878dacd5f0120476f9b836ccf8699ea (patch) | |
tree | 43c81a5697976af080e58e41ec84c7f5c7c29fbe | |
parent | 6097d55e10a7e190279e99318a0e075c8d1dce9e (diff) | |
parent | 4fcd504edbf7c793325511c2df8dcd083958e28a (diff) |
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
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; |