diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-15 21:50:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-15 21:50:40 -0400 |
commit | 8649efb2f8750dcabff018a27784bab4ecb9f88f (patch) | |
tree | 4351aa7377c2042be5963d0f8b5600a1eb221a59 | |
parent | 5fd09ba68297c967f5ba6bea9c3b444d34f80ee5 (diff) | |
parent | baf5964ecfe19a0109fe2e497e72840ce0f488e6 (diff) |
Merge tag 'for-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply and reset updates from Sebastian Reichel:
"Core:
- Add over-current health state
- Add standard, adaptive and custom charge types
- Add new properties for start/end charge threshold
New Drivers / Hardware:
- UCS1002 Programmable USB Port Power Controller
- Ingenic JZ47xx Battery Fuel Gauge
- AXP20x USB Power: Add AXP813 support
- AT91 poweroff: Add SAM9X60 support
- OLPC battery: Add XO-1.5 and XO-1.75 support
Misc Changes:
- syscon-reboot: support mask property
- AXP288 fuel gauge: Blacklist ACEPC T8/T11. Looks like some vendor
thought it's a good idea to build a desktop system with a fuel
gauge, that slowly "discharges"...
- cpcap-battery: Fix calculation errors
- misc fixes"
* tag 'for-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (54 commits)
power: supply: olpc_battery: force the le/be casts
power: supply: ucs1002: Fix build error without CONFIG_REGULATOR
power: supply: ucs1002: Fix wrong return value checking
power: supply: Add driver for Microchip UCS1002
dt-bindings: power: supply: Add bindings for Microchip UCS1002
power: supply: core: Add POWER_SUPPLY_HEALTH_OVERCURRENT constant
power: supply: core: fix clang -Wunsequenced
power: supply: core: Add missing documentation for CHARGE_CONTROL_* properties
power: supply: core: Add CHARGE_CONTROL_{START_THRESHOLD,END_THRESHOLD} properties
power: supply: core: Add Standard, Adaptive, and Custom charge types
power: supply: axp288_fuel_gauge: Add ACEPC T8 and T11 mini PCs to the blacklist
power: supply: bq27xxx_battery: Notify also about status changes
power: supply: olpc_battery: Have the framework register sysfs files for us
power: supply: olpc_battery: Add OLPC XO 1.75 support
power: supply: olpc_battery: Avoid using platform_info
power: supply: olpc_battery: Use devm_power_supply_register()
power: supply: olpc_battery: Move priv data to a struct
power: supply: olpc_battery: Use DT to get battery version
x86/platform/olpc: Use a correct version when making up a battery node
x86/platform/olpc: Trivial code move in DT fixup
...
33 files changed, 1611 insertions, 271 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 5e23e22dce1b..b77e30b9014e 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power | |||
@@ -114,15 +114,60 @@ Description: | |||
114 | Access: Read | 114 | Access: Read |
115 | Valid values: Represented in microamps | 115 | Valid values: Represented in microamps |
116 | 116 | ||
117 | What: /sys/class/power_supply/<supply_name>/charge_control_limit | ||
118 | Date: Oct 2012 | ||
119 | Contact: linux-pm@vger.kernel.org | ||
120 | Description: | ||
121 | Maximum allowable charging current. Used for charge rate | ||
122 | throttling for thermal cooling or improving battery health. | ||
123 | |||
124 | Access: Read, Write | ||
125 | Valid values: Represented in microamps | ||
126 | |||
127 | What: /sys/class/power_supply/<supply_name>/charge_control_limit_max | ||
128 | Date: Oct 2012 | ||
129 | Contact: linux-pm@vger.kernel.org | ||
130 | Description: | ||
131 | Maximum legal value for the charge_control_limit property. | ||
132 | |||
133 | Access: Read | ||
134 | Valid values: Represented in microamps | ||
135 | |||
136 | What: /sys/class/power_supply/<supply_name>/charge_control_start_threshold | ||
137 | Date: April 2019 | ||
138 | Contact: linux-pm@vger.kernel.org | ||
139 | Description: | ||
140 | Represents a battery percentage level, below which charging will | ||
141 | begin. | ||
142 | |||
143 | Access: Read, Write | ||
144 | Valid values: 0 - 100 (percent) | ||
145 | |||
146 | What: /sys/class/power_supply/<supply_name>/charge_control_end_threshold | ||
147 | Date: April 2019 | ||
148 | Contact: linux-pm@vger.kernel.org | ||
149 | Description: | ||
150 | Represents a battery percentage level, above which charging will | ||
151 | stop. | ||
152 | |||
153 | Access: Read, Write | ||
154 | Valid values: 0 - 100 (percent) | ||
155 | |||
117 | What: /sys/class/power_supply/<supply_name>/charge_type | 156 | What: /sys/class/power_supply/<supply_name>/charge_type |
118 | Date: July 2009 | 157 | Date: July 2009 |
119 | Contact: linux-pm@vger.kernel.org | 158 | Contact: linux-pm@vger.kernel.org |
120 | Description: | 159 | Description: |
121 | Represents the type of charging currently being applied to the | 160 | Represents the type of charging currently being applied to the |
122 | battery. | 161 | battery. "Trickle", "Fast", and "Standard" all mean different |
162 | charging speeds. "Adaptive" means that the charger uses some | ||
163 | algorithm to adjust the charge rate dynamically, without | ||
164 | any user configuration required. "Custom" means that the charger | ||
165 | uses the charge_control_* properties as configuration for some | ||
166 | different algorithm. | ||
123 | 167 | ||
124 | Access: Read | 168 | Access: Read, Write |
125 | Valid values: "Unknown", "N/A", "Trickle", "Fast" | 169 | Valid values: "Unknown", "N/A", "Trickle", "Fast", "Standard", |
170 | "Adaptive", "Custom" | ||
126 | 171 | ||
127 | What: /sys/class/power_supply/<supply_name>/charge_term_current | 172 | What: /sys/class/power_supply/<supply_name>/charge_term_current |
128 | Date: July 2014 | 173 | Date: July 2014 |
diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt index e61d00e25b95..9fbde401a090 100644 --- a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt | |||
@@ -84,7 +84,7 @@ SHDWC SAMA5D2-Compatible Shutdown Controller | |||
84 | 1) shdwc node | 84 | 1) shdwc node |
85 | 85 | ||
86 | required properties: | 86 | required properties: |
87 | - compatible: should be "atmel,sama5d2-shdwc". | 87 | - compatible: should be "atmel,sama5d2-shdwc" or "microchip,sam9x60-shdwc". |
88 | - reg: should contain registers location and length | 88 | - reg: should contain registers location and length |
89 | - clocks: phandle to input clock. | 89 | - clocks: phandle to input clock. |
90 | - #address-cells: should be one. The cell is the wake-up input index. | 90 | - #address-cells: should be one. The cell is the wake-up input index. |
@@ -96,6 +96,9 @@ optional properties: | |||
96 | microseconds. It's usually a board-related property. | 96 | microseconds. It's usually a board-related property. |
97 | - atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. | 97 | - atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. |
98 | 98 | ||
99 | optional microchip,sam9x60-shdwc properties: | ||
100 | - atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. | ||
101 | |||
99 | The node contains child nodes for each wake-up input that the platform uses. | 102 | The node contains child nodes for each wake-up input that the platform uses. |
100 | 103 | ||
101 | 2) input nodes | 104 | 2) input nodes |
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt b/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt index 11906316b43d..e23dea8344f8 100644 --- a/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt | |||
@@ -3,13 +3,20 @@ Generic SYSCON mapped register reset driver | |||
3 | This is a generic reset driver using syscon to map the reset register. | 3 | This is a generic reset driver using syscon to map the reset register. |
4 | The reset is generally performed with a write to the reset register | 4 | The reset is generally performed with a write to the reset register |
5 | defined by the register map pointed by syscon reference plus the offset | 5 | defined by the register map pointed by syscon reference plus the offset |
6 | with the mask defined in the reboot node. | 6 | with the value and mask defined in the reboot node. |
7 | 7 | ||
8 | Required properties: | 8 | Required properties: |
9 | - compatible: should contain "syscon-reboot" | 9 | - compatible: should contain "syscon-reboot" |
10 | - regmap: this is phandle to the register map node | 10 | - regmap: this is phandle to the register map node |
11 | - offset: offset in the register map for the reboot register (in bytes) | 11 | - offset: offset in the register map for the reboot register (in bytes) |
12 | - mask: the reset value written to the reboot register (32 bit access) | 12 | - value: the reset value written to the reboot register (32 bit access) |
13 | |||
14 | Optional properties: | ||
15 | - mask: update only the register bits defined by the mask (32 bit) | ||
16 | |||
17 | Legacy usage: | ||
18 | If a node doesn't contain a value property but contains a mask property, the | ||
19 | mask property is used as the value. | ||
13 | 20 | ||
14 | Default will be little endian mode, 32 bit access only. | 21 | Default will be little endian mode, 32 bit access only. |
15 | 22 | ||
diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt index ba8d35f66cbe..b2d4968fde7d 100644 --- a/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt +++ b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt | |||
@@ -4,6 +4,7 @@ Required Properties: | |||
4 | -compatible: One of: "x-powers,axp202-usb-power-supply" | 4 | -compatible: One of: "x-powers,axp202-usb-power-supply" |
5 | "x-powers,axp221-usb-power-supply" | 5 | "x-powers,axp221-usb-power-supply" |
6 | "x-powers,axp223-usb-power-supply" | 6 | "x-powers,axp223-usb-power-supply" |
7 | "x-powers,axp813-usb-power-supply" | ||
7 | 8 | ||
8 | The AXP223 PMIC shares most of its behaviour with the AXP221 but has slight | 9 | The AXP223 PMIC shares most of its behaviour with the AXP221 but has slight |
9 | variations such as the former being able to set the VBUS power supply max | 10 | variations such as the former being able to set the VBUS power supply max |
diff --git a/Documentation/devicetree/bindings/power/supply/gpio-charger.txt b/Documentation/devicetree/bindings/power/supply/gpio-charger.txt index adbb5dc5b6e9..0fb33b2c62a6 100644 --- a/Documentation/devicetree/bindings/power/supply/gpio-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/gpio-charger.txt | |||
@@ -14,13 +14,17 @@ Required properties : | |||
14 | usb-cdp (USB charging downstream port) | 14 | usb-cdp (USB charging downstream port) |
15 | usb-aca (USB accessory charger adapter) | 15 | usb-aca (USB accessory charger adapter) |
16 | 16 | ||
17 | Optional properties: | ||
18 | - charge-status-gpios: GPIO indicating whether a battery is charging. | ||
19 | |||
17 | Example: | 20 | Example: |
18 | 21 | ||
19 | usb_charger: charger { | 22 | usb_charger: charger { |
20 | compatible = "gpio-charger"; | 23 | compatible = "gpio-charger"; |
21 | charger-type = "usb-sdp"; | 24 | charger-type = "usb-sdp"; |
22 | gpios = <&gpf0 2 0 0 0>; | 25 | gpios = <&gpd 28 GPIO_ACTIVE_LOW>; |
23 | } | 26 | charge-status-gpios = <&gpc 27 GPIO_ACTIVE_LOW>; |
27 | }; | ||
24 | 28 | ||
25 | battery { | 29 | battery { |
26 | power-supplies = <&usb_charger>; | 30 | power-supplies = <&usb_charger>; |
diff --git a/Documentation/devicetree/bindings/power/supply/ingenic,battery.txt b/Documentation/devicetree/bindings/power/supply/ingenic,battery.txt new file mode 100644 index 000000000000..66430bf73815 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/ingenic,battery.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | * Ingenic JZ47xx battery bindings | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: Must be "ingenic,jz4740-battery". | ||
6 | - io-channels: phandle and IIO specifier pair to the IIO device. | ||
7 | Format described in iio-bindings.txt. | ||
8 | - monitored-battery: phandle to a "simple-battery" compatible node. | ||
9 | |||
10 | The "monitored-battery" property must be a phandle to a node using the format | ||
11 | described in battery.txt, with the following properties being required: | ||
12 | |||
13 | - voltage-min-design-microvolt: Drained battery voltage. | ||
14 | - voltage-max-design-microvolt: Fully charged battery voltage. | ||
15 | |||
16 | Example: | ||
17 | |||
18 | #include <dt-bindings/iio/adc/ingenic,adc.h> | ||
19 | |||
20 | simple_battery: battery { | ||
21 | compatible = "simple-battery"; | ||
22 | voltage-min-design-microvolt = <3600000>; | ||
23 | voltage-max-design-microvolt = <4200000>; | ||
24 | }; | ||
25 | |||
26 | ingenic_battery { | ||
27 | compatible = "ingenic,jz4740-battery"; | ||
28 | io-channels = <&adc INGENIC_ADC_BATTERY>; | ||
29 | io-channel-names = "battery"; | ||
30 | monitored-battery = <&simple_battery>; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt b/Documentation/devicetree/bindings/power/supply/lt3651-charger.txt index 71f2840e8209..40811ff8de10 100644 --- a/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/lt3651-charger.txt | |||
@@ -1,14 +1,16 @@ | |||
1 | ltc3651-charger | 1 | Analog Devices LT3651 Charger Power Supply bindings: lt3651-charger |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: "lltc,ltc3651-charger" | 4 | - compatible: Should contain one of the following: |
5 | * "lltc,ltc3651-charger", (DEPRECATED: Use "lltc,lt3651-charger") | ||
6 | * "lltc,lt3651-charger" | ||
5 | - lltc,acpr-gpios: Connect to ACPR output. See remark below. | 7 | - lltc,acpr-gpios: Connect to ACPR output. See remark below. |
6 | 8 | ||
7 | Optional properties: | 9 | Optional properties: |
8 | - lltc,fault-gpios: Connect to FAULT output. See remark below. | 10 | - lltc,fault-gpios: Connect to FAULT output. See remark below. |
9 | - lltc,chrg-gpios: Connect to CHRG output. See remark below. | 11 | - lltc,chrg-gpios: Connect to CHRG output. See remark below. |
10 | 12 | ||
11 | The ltc3651 outputs are open-drain type and active low. The driver assumes the | 13 | The lt3651 outputs are open-drain type and active low. The driver assumes the |
12 | GPIO reports "active" when the output is asserted, so if the pins have been | 14 | GPIO reports "active" when the output is asserted, so if the pins have been |
13 | connected directly, the GPIO flags should be set to active low also. | 15 | connected directly, the GPIO flags should be set to active low also. |
14 | 16 | ||
@@ -20,7 +22,7 @@ attributes to detect changes. | |||
20 | Example: | 22 | Example: |
21 | 23 | ||
22 | charger: battery-charger { | 24 | charger: battery-charger { |
23 | compatible = "lltc,ltc3651-charger"; | 25 | compatible = "lltc,lt3651-charger"; |
24 | lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>; | 26 | lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>; |
25 | lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>; | 27 | lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>; |
26 | lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>; | 28 | lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>; |
diff --git a/Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt b/Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt new file mode 100644 index 000000000000..1d284ad816bf --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | Microchip UCS1002 USB Port Power Controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : Should be "microchip,ucs1002"; | ||
5 | - reg : I2C slave address | ||
6 | |||
7 | Optional properties: | ||
8 | - interrupts : A list of interrupts lines present (could be either | ||
9 | corresponding to A_DET# pin, ALERT# pin, or both) | ||
10 | - interrupt-names : A list of interrupt names. Should contain (if | ||
11 | present): | ||
12 | - "a_det" for line connected to A_DET# pin | ||
13 | - "alert" for line connected to ALERT# pin | ||
14 | Both are expected to be IRQ_TYPE_EDGE_BOTH | ||
15 | Example: | ||
16 | |||
17 | &i2c3 { | ||
18 | charger@32 { | ||
19 | compatible = "microchip,ucs1002"; | ||
20 | pinctrl-names = "default"; | ||
21 | pinctrl-0 = <&pinctrl_ucs1002_pins>; | ||
22 | reg = <0x32>; | ||
23 | interrupts-extended = <&gpio5 2 IRQ_TYPE_EDGE_BOTH>, | ||
24 | <&gpio3 21 IRQ_TYPE_EDGE_BOTH>; | ||
25 | interrupt-names = "a_det", "alert"; | ||
26 | }; | ||
27 | }; | ||
diff --git a/Documentation/devicetree/bindings/power/supply/olpc_battery.txt b/Documentation/devicetree/bindings/power/supply/olpc_battery.txt index c8901b3992d9..8d87d6b35a98 100644 --- a/Documentation/devicetree/bindings/power/supply/olpc_battery.txt +++ b/Documentation/devicetree/bindings/power/supply/olpc_battery.txt | |||
@@ -2,4 +2,4 @@ OLPC battery | |||
2 | ~~~~~~~~~~~~ | 2 | ~~~~~~~~~~~~ |
3 | 3 | ||
4 | Required properties: | 4 | Required properties: |
5 | - compatible : "olpc,xo1-battery" | 5 | - compatible : "olpc,xo1-battery" or "olpc,xo1.5-battery" |
diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c index ac9e7bf49b66..0296c5b55e6f 100644 --- a/arch/x86/platform/olpc/olpc_dt.c +++ b/arch/x86/platform/olpc/olpc_dt.c | |||
@@ -220,10 +220,26 @@ static u32 __init olpc_dt_get_board_revision(void) | |||
220 | return be32_to_cpu(rev); | 220 | return be32_to_cpu(rev); |
221 | } | 221 | } |
222 | 222 | ||
223 | int olpc_dt_compatible_match(phandle node, const char *compat) | ||
224 | { | ||
225 | char buf[64], *p; | ||
226 | int plen, len; | ||
227 | |||
228 | plen = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf)); | ||
229 | if (plen <= 0) | ||
230 | return 0; | ||
231 | |||
232 | len = strlen(compat); | ||
233 | for (p = buf; p < buf + plen; p += strlen(p) + 1) { | ||
234 | if (strcmp(p, compat) == 0) | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
223 | void __init olpc_dt_fixup(void) | 241 | void __init olpc_dt_fixup(void) |
224 | { | 242 | { |
225 | int r; | ||
226 | char buf[64]; | ||
227 | phandle node; | 243 | phandle node; |
228 | u32 board_rev; | 244 | u32 board_rev; |
229 | 245 | ||
@@ -231,41 +247,66 @@ void __init olpc_dt_fixup(void) | |||
231 | if (!node) | 247 | if (!node) |
232 | return; | 248 | return; |
233 | 249 | ||
234 | /* | ||
235 | * If the battery node has a compatible property, we are running a new | ||
236 | * enough firmware and don't have fixups to make. | ||
237 | */ | ||
238 | r = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf)); | ||
239 | if (r > 0) | ||
240 | return; | ||
241 | |||
242 | pr_info("PROM DT: Old firmware detected, applying fixes\n"); | ||
243 | |||
244 | /* Add olpc,xo1-battery compatible marker to battery node */ | ||
245 | olpc_dt_interpret("\" /battery@0\" find-device" | ||
246 | " \" olpc,xo1-battery\" +compatible" | ||
247 | " device-end"); | ||
248 | |||
249 | board_rev = olpc_dt_get_board_revision(); | 250 | board_rev = olpc_dt_get_board_revision(); |
250 | if (!board_rev) | 251 | if (!board_rev) |
251 | return; | 252 | return; |
252 | 253 | ||
253 | if (board_rev >= olpc_board_pre(0xd0)) { | 254 | if (board_rev >= olpc_board_pre(0xd0)) { |
254 | /* XO-1.5: add dcon device */ | 255 | /* XO-1.5 */ |
255 | olpc_dt_interpret("\" /pci/display@1\" find-device" | 256 | |
256 | " new-device" | 257 | if (olpc_dt_compatible_match(node, "olpc,xo1.5-battery")) |
257 | " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible" | 258 | return; |
258 | " finish-device device-end"); | 259 | |
260 | /* Add olpc,xo1.5-battery compatible marker to battery node */ | ||
261 | olpc_dt_interpret("\" /battery@0\" find-device"); | ||
262 | olpc_dt_interpret(" \" olpc,xo1.5-battery\" +compatible"); | ||
263 | olpc_dt_interpret("device-end"); | ||
264 | |||
265 | if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) { | ||
266 | /* | ||
267 | * If we have a olpc,xo1-battery compatible, then we're | ||
268 | * running a new enough firmware that already has | ||
269 | * the dcon node. | ||
270 | */ | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | /* Add dcon device */ | ||
275 | olpc_dt_interpret("\" /pci/display@1\" find-device"); | ||
276 | olpc_dt_interpret(" new-device"); | ||
277 | olpc_dt_interpret(" \" dcon\" device-name"); | ||
278 | olpc_dt_interpret(" \" olpc,xo1-dcon\" +compatible"); | ||
279 | olpc_dt_interpret(" finish-device"); | ||
280 | olpc_dt_interpret("device-end"); | ||
259 | } else { | 281 | } else { |
260 | /* XO-1: add dcon device, mark RTC as olpc,xo1-rtc */ | 282 | /* XO-1 */ |
261 | olpc_dt_interpret("\" /pci/display@1,1\" find-device" | 283 | |
262 | " new-device" | 284 | if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) { |
263 | " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible" | 285 | /* |
264 | " finish-device device-end" | 286 | * If we have a olpc,xo1-battery compatible, then we're |
265 | " \" /rtc\" find-device" | 287 | * running a new enough firmware that already has |
266 | " \" olpc,xo1-rtc\" +compatible" | 288 | * the dcon and RTC nodes. |
267 | " device-end"); | 289 | */ |
290 | return; | ||
291 | } | ||
292 | |||
293 | /* Add dcon device, mark RTC as olpc,xo1-rtc */ | ||
294 | olpc_dt_interpret("\" /pci/display@1,1\" find-device"); | ||
295 | olpc_dt_interpret(" new-device"); | ||
296 | olpc_dt_interpret(" \" dcon\" device-name"); | ||
297 | olpc_dt_interpret(" \" olpc,xo1-dcon\" +compatible"); | ||
298 | olpc_dt_interpret(" finish-device"); | ||
299 | olpc_dt_interpret("device-end"); | ||
300 | |||
301 | olpc_dt_interpret("\" /rtc\" find-device"); | ||
302 | olpc_dt_interpret(" \" olpc,xo1-rtc\" +compatible"); | ||
303 | olpc_dt_interpret("device-end"); | ||
268 | } | 304 | } |
305 | |||
306 | /* Add olpc,xo1-battery compatible marker to battery node */ | ||
307 | olpc_dt_interpret("\" /battery@0\" find-device"); | ||
308 | olpc_dt_interpret(" \" olpc,xo1-battery\" +compatible"); | ||
309 | olpc_dt_interpret("device-end"); | ||
269 | } | 310 | } |
270 | 311 | ||
271 | void __init olpc_dt_build_devicetree(void) | 312 | void __init olpc_dt_build_devicetree(void) |
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 06ca3f7fcc44..4a5eff3f18bc 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c | |||
@@ -733,11 +733,11 @@ static int iio_channel_read_avail(struct iio_channel *chan, | |||
733 | vals, type, length, info); | 733 | vals, type, length, info); |
734 | } | 734 | } |
735 | 735 | ||
736 | int iio_read_avail_channel_raw(struct iio_channel *chan, | 736 | int iio_read_avail_channel_attribute(struct iio_channel *chan, |
737 | const int **vals, int *length) | 737 | const int **vals, int *type, int *length, |
738 | enum iio_chan_info_enum attribute) | ||
738 | { | 739 | { |
739 | int ret; | 740 | int ret; |
740 | int type; | ||
741 | 741 | ||
742 | mutex_lock(&chan->indio_dev->info_exist_lock); | 742 | mutex_lock(&chan->indio_dev->info_exist_lock); |
743 | if (!chan->indio_dev->info) { | 743 | if (!chan->indio_dev->info) { |
@@ -745,11 +745,23 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, | |||
745 | goto err_unlock; | 745 | goto err_unlock; |
746 | } | 746 | } |
747 | 747 | ||
748 | ret = iio_channel_read_avail(chan, | 748 | ret = iio_channel_read_avail(chan, vals, type, length, attribute); |
749 | vals, &type, length, IIO_CHAN_INFO_RAW); | ||
750 | err_unlock: | 749 | err_unlock: |
751 | mutex_unlock(&chan->indio_dev->info_exist_lock); | 750 | mutex_unlock(&chan->indio_dev->info_exist_lock); |
752 | 751 | ||
752 | return ret; | ||
753 | } | ||
754 | EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); | ||
755 | |||
756 | int iio_read_avail_channel_raw(struct iio_channel *chan, | ||
757 | const int **vals, int *length) | ||
758 | { | ||
759 | int ret; | ||
760 | int type; | ||
761 | |||
762 | ret = iio_read_avail_channel_attribute(chan, vals, &type, length, | ||
763 | IIO_CHAN_INFO_RAW); | ||
764 | |||
753 | if (ret >= 0 && type != IIO_VAL_INT) | 765 | if (ret >= 0 && type != IIO_VAL_INT) |
754 | /* raw values are assumed to be IIO_VAL_INT */ | 766 | /* raw values are assumed to be IIO_VAL_INT */ |
755 | ret = -EINVAL; | 767 | ret = -EINVAL; |
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 2b686c55b717..e341cc5c0ea6 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c | |||
@@ -57,15 +57,21 @@ | |||
57 | 57 | ||
58 | #define SHDW_WK_PIN(reg, cfg) ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input)) | 58 | #define SHDW_WK_PIN(reg, cfg) ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input)) |
59 | #define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1) | 59 | #define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1) |
60 | #define SHDW_RTTWK(reg, cfg) (((reg) >> ((cfg)->sr_rttwk_shift)) & 0x1) | ||
60 | #define SHDW_RTCWKEN(cfg) (1 << ((cfg)->mr_rtcwk_shift)) | 61 | #define SHDW_RTCWKEN(cfg) (1 << ((cfg)->mr_rtcwk_shift)) |
62 | #define SHDW_RTTWKEN(cfg) (1 << ((cfg)->mr_rttwk_shift)) | ||
61 | 63 | ||
62 | #define DBC_PERIOD_US(x) DIV_ROUND_UP_ULL((1000000 * (x)), \ | 64 | #define DBC_PERIOD_US(x) DIV_ROUND_UP_ULL((1000000 * (x)), \ |
63 | SLOW_CLOCK_FREQ) | 65 | SLOW_CLOCK_FREQ) |
64 | 66 | ||
67 | #define SHDW_CFG_NOT_USED (32) | ||
68 | |||
65 | struct shdwc_config { | 69 | struct shdwc_config { |
66 | u8 wkup_pin_input; | 70 | u8 wkup_pin_input; |
67 | u8 mr_rtcwk_shift; | 71 | u8 mr_rtcwk_shift; |
72 | u8 mr_rttwk_shift; | ||
68 | u8 sr_rtcwk_shift; | 73 | u8 sr_rtcwk_shift; |
74 | u8 sr_rttwk_shift; | ||
69 | }; | 75 | }; |
70 | 76 | ||
71 | struct shdwc { | 77 | struct shdwc { |
@@ -104,6 +110,8 @@ static void __init at91_wakeup_status(struct platform_device *pdev) | |||
104 | reason = "WKUP pin"; | 110 | reason = "WKUP pin"; |
105 | else if (SHDW_RTCWK(reg, shdw->cfg)) | 111 | else if (SHDW_RTCWK(reg, shdw->cfg)) |
106 | reason = "RTC"; | 112 | reason = "RTC"; |
113 | else if (SHDW_RTTWK(reg, shdw->cfg)) | ||
114 | reason = "RTT"; | ||
107 | 115 | ||
108 | pr_info("AT91: Wake-Up source: %s\n", reason); | 116 | pr_info("AT91: Wake-Up source: %s\n", reason); |
109 | } | 117 | } |
@@ -221,6 +229,9 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev) | |||
221 | if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) | 229 | if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) |
222 | mode |= SHDW_RTCWKEN(shdw->cfg); | 230 | mode |= SHDW_RTCWKEN(shdw->cfg); |
223 | 231 | ||
232 | if (of_property_read_bool(np, "atmel,wakeup-rtt-timer")) | ||
233 | mode |= SHDW_RTTWKEN(shdw->cfg); | ||
234 | |||
224 | dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode); | 235 | dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode); |
225 | writel(mode, shdw->shdwc_base + AT91_SHDW_MR); | 236 | writel(mode, shdw->shdwc_base + AT91_SHDW_MR); |
226 | 237 | ||
@@ -231,13 +242,27 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev) | |||
231 | static const struct shdwc_config sama5d2_shdwc_config = { | 242 | static const struct shdwc_config sama5d2_shdwc_config = { |
232 | .wkup_pin_input = 0, | 243 | .wkup_pin_input = 0, |
233 | .mr_rtcwk_shift = 17, | 244 | .mr_rtcwk_shift = 17, |
245 | .mr_rttwk_shift = SHDW_CFG_NOT_USED, | ||
234 | .sr_rtcwk_shift = 5, | 246 | .sr_rtcwk_shift = 5, |
247 | .sr_rttwk_shift = SHDW_CFG_NOT_USED, | ||
248 | }; | ||
249 | |||
250 | static const struct shdwc_config sam9x60_shdwc_config = { | ||
251 | .wkup_pin_input = 0, | ||
252 | .mr_rtcwk_shift = 17, | ||
253 | .mr_rttwk_shift = 16, | ||
254 | .sr_rtcwk_shift = 5, | ||
255 | .sr_rttwk_shift = 4, | ||
235 | }; | 256 | }; |
236 | 257 | ||
237 | static const struct of_device_id at91_shdwc_of_match[] = { | 258 | static const struct of_device_id at91_shdwc_of_match[] = { |
238 | { | 259 | { |
239 | .compatible = "atmel,sama5d2-shdwc", | 260 | .compatible = "atmel,sama5d2-shdwc", |
240 | .data = &sama5d2_shdwc_config, | 261 | .data = &sama5d2_shdwc_config, |
262 | }, | ||
263 | { | ||
264 | .compatible = "microchip,sam9x60-shdwc", | ||
265 | .data = &sam9x60_shdwc_config, | ||
241 | }, { | 266 | }, { |
242 | /*sentinel*/ | 267 | /*sentinel*/ |
243 | } | 268 | } |
diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c index 7d0d269a0837..5a6bb638c331 100644 --- a/drivers/power/reset/syscon-reboot.c +++ b/drivers/power/reset/syscon-reboot.c | |||
@@ -27,6 +27,7 @@ | |||
27 | struct syscon_reboot_context { | 27 | struct syscon_reboot_context { |
28 | struct regmap *map; | 28 | struct regmap *map; |
29 | u32 offset; | 29 | u32 offset; |
30 | u32 value; | ||
30 | u32 mask; | 31 | u32 mask; |
31 | struct notifier_block restart_handler; | 32 | struct notifier_block restart_handler; |
32 | }; | 33 | }; |
@@ -39,7 +40,7 @@ static int syscon_restart_handle(struct notifier_block *this, | |||
39 | restart_handler); | 40 | restart_handler); |
40 | 41 | ||
41 | /* Issue the reboot */ | 42 | /* Issue the reboot */ |
42 | regmap_write(ctx->map, ctx->offset, ctx->mask); | 43 | regmap_update_bits(ctx->map, ctx->offset, ctx->mask, ctx->value); |
43 | 44 | ||
44 | mdelay(1000); | 45 | mdelay(1000); |
45 | 46 | ||
@@ -51,6 +52,7 @@ static int syscon_reboot_probe(struct platform_device *pdev) | |||
51 | { | 52 | { |
52 | struct syscon_reboot_context *ctx; | 53 | struct syscon_reboot_context *ctx; |
53 | struct device *dev = &pdev->dev; | 54 | struct device *dev = &pdev->dev; |
55 | int mask_err, value_err; | ||
54 | int err; | 56 | int err; |
55 | 57 | ||
56 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | 58 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
@@ -64,8 +66,21 @@ static int syscon_reboot_probe(struct platform_device *pdev) | |||
64 | if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) | 66 | if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) |
65 | return -EINVAL; | 67 | return -EINVAL; |
66 | 68 | ||
67 | if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask)) | 69 | value_err = of_property_read_u32(pdev->dev.of_node, "value", &ctx->value); |
70 | mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask); | ||
71 | if (value_err && mask_err) { | ||
72 | dev_err(dev, "unable to read 'value' and 'mask'"); | ||
68 | return -EINVAL; | 73 | return -EINVAL; |
74 | } | ||
75 | |||
76 | if (value_err) { | ||
77 | /* support old binding */ | ||
78 | ctx->value = ctx->mask; | ||
79 | ctx->mask = 0xFFFFFFFF; | ||
80 | } else if (mask_err) { | ||
81 | /* support value without mask*/ | ||
82 | ctx->mask = 0xFFFFFFFF; | ||
83 | } | ||
69 | 84 | ||
70 | ctx->restart_handler.notifier_call = syscon_restart_handle; | 85 | ctx->restart_handler.notifier_call = syscon_restart_handle; |
71 | ctx->restart_handler.priority = 192; | 86 | ctx->restart_handler.priority = 192; |
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 0230c96fa94d..26dacdab03cc 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig | |||
@@ -169,6 +169,17 @@ config BATTERY_COLLIE | |||
169 | Say Y to enable support for the battery on the Sharp Zaurus | 169 | Say Y to enable support for the battery on the Sharp Zaurus |
170 | SL-5500 (collie) models. | 170 | SL-5500 (collie) models. |
171 | 171 | ||
172 | config BATTERY_INGENIC | ||
173 | tristate "Ingenic JZ47xx SoCs battery driver" | ||
174 | depends on MIPS || COMPILE_TEST | ||
175 | depends on INGENIC_ADC | ||
176 | help | ||
177 | Choose this option if you want to monitor battery status on | ||
178 | Ingenic JZ47xx SoC based devices. | ||
179 | |||
180 | This driver can also be built as a module. If so, the module will be | ||
181 | called ingenic-battery. | ||
182 | |||
172 | config BATTERY_IPAQ_MICRO | 183 | config BATTERY_IPAQ_MICRO |
173 | tristate "iPAQ Atmel Micro ASIC battery driver" | 184 | tristate "iPAQ Atmel Micro ASIC battery driver" |
174 | depends on MFD_IPAQ_MICRO | 185 | depends on MFD_IPAQ_MICRO |
@@ -475,12 +486,12 @@ config CHARGER_MANAGER | |||
475 | runtime and in suspend-to-RAM by waking up the system periodically | 486 | runtime and in suspend-to-RAM by waking up the system periodically |
476 | with help of suspend_again support. | 487 | with help of suspend_again support. |
477 | 488 | ||
478 | config CHARGER_LTC3651 | 489 | config CHARGER_LT3651 |
479 | tristate "LTC3651 charger" | 490 | tristate "Analog Devices LT3651 charger" |
480 | depends on GPIOLIB | 491 | depends on GPIOLIB |
481 | help | 492 | help |
482 | Say Y to include support for the LTC3651 battery charger which reports | 493 | Say Y to include support for the Analog Devices (Linear Technology) |
483 | its status via GPIO lines. | 494 | LT3651 battery charger which reports its status via GPIO lines. |
484 | 495 | ||
485 | config CHARGER_MAX14577 | 496 | config CHARGER_MAX14577 |
486 | tristate "Maxim MAX14577/77836 battery charger driver" | 497 | tristate "Maxim MAX14577/77836 battery charger driver" |
@@ -667,4 +678,14 @@ config FUEL_GAUGE_SC27XX | |||
667 | Say Y here to enable support for fuel gauge with SC27XX | 678 | Say Y here to enable support for fuel gauge with SC27XX |
668 | PMIC chips. | 679 | PMIC chips. |
669 | 680 | ||
681 | config CHARGER_UCS1002 | ||
682 | tristate "Microchip UCS1002 USB Port Power Controller" | ||
683 | depends on I2C | ||
684 | depends on OF | ||
685 | depends on REGULATOR | ||
686 | select REGMAP_I2C | ||
687 | help | ||
688 | Say Y to enable support for Microchip UCS1002 Programmable | ||
689 | USB Port Power Controller with Charger Emulation. | ||
690 | |||
670 | endif # POWER_SUPPLY | 691 | endif # POWER_SUPPLY |
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index b73eb8c5c1a9..f208273f9686 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | |||
34 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 34 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o |
35 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o | 35 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o |
36 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o | 36 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o |
37 | obj-$(CONFIG_BATTERY_INGENIC) += ingenic-battery.o | ||
37 | obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o | 38 | obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o |
38 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o | 39 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o |
39 | obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o | 40 | obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o |
@@ -67,7 +68,7 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o | |||
67 | obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o | 68 | obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o |
68 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o | 69 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o |
69 | obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o | 70 | obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o |
70 | obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o | 71 | obj-$(CONFIG_CHARGER_LT3651) += lt3651-charger.o |
71 | obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o | 72 | obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o |
72 | obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o | 73 | obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o |
73 | obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o | 74 | obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o |
@@ -88,3 +89,4 @@ obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o | |||
88 | obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o | 89 | obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o |
89 | obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o | 90 | obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o |
90 | obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o | 91 | obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o |
92 | obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o | ||
diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 7b2b69916f48..f6a66979cbb5 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c | |||
@@ -508,6 +508,7 @@ int ab8500_bm_of_probe(struct device *dev, | |||
508 | btech = of_get_property(battery_node, "stericsson,battery-type", NULL); | 508 | btech = of_get_property(battery_node, "stericsson,battery-type", NULL); |
509 | if (!btech) { | 509 | if (!btech) { |
510 | dev_warn(dev, "missing property battery-name/type\n"); | 510 | dev_warn(dev, "missing property battery-name/type\n"); |
511 | of_node_put(battery_node); | ||
511 | return -EINVAL; | 512 | return -EINVAL; |
512 | } | 513 | } |
513 | 514 | ||
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index f52fe77edb6f..d2b1255ee1cc 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/iio/consumer.h> | 26 | #include <linux/iio/consumer.h> |
27 | #include <linux/workqueue.h> | ||
27 | 28 | ||
28 | #define DRVNAME "axp20x-usb-power-supply" | 29 | #define DRVNAME "axp20x-usb-power-supply" |
29 | 30 | ||
@@ -36,16 +37,27 @@ | |||
36 | #define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3) | 37 | #define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3) |
37 | #define AXP20X_VBUS_VHOLD_OFFSET 3 | 38 | #define AXP20X_VBUS_VHOLD_OFFSET 3 |
38 | #define AXP20X_VBUS_CLIMIT_MASK 3 | 39 | #define AXP20X_VBUS_CLIMIT_MASK 3 |
39 | #define AXP20X_VBUC_CLIMIT_900mA 0 | 40 | #define AXP20X_VBUS_CLIMIT_900mA 0 |
40 | #define AXP20X_VBUC_CLIMIT_500mA 1 | 41 | #define AXP20X_VBUS_CLIMIT_500mA 1 |
41 | #define AXP20X_VBUC_CLIMIT_100mA 2 | 42 | #define AXP20X_VBUS_CLIMIT_100mA 2 |
42 | #define AXP20X_VBUC_CLIMIT_NONE 3 | 43 | #define AXP20X_VBUS_CLIMIT_NONE 3 |
44 | |||
45 | #define AXP813_VBUS_CLIMIT_900mA 0 | ||
46 | #define AXP813_VBUS_CLIMIT_1500mA 1 | ||
47 | #define AXP813_VBUS_CLIMIT_2000mA 2 | ||
48 | #define AXP813_VBUS_CLIMIT_2500mA 3 | ||
43 | 49 | ||
44 | #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) | 50 | #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) |
45 | #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) | 51 | #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) |
46 | 52 | ||
47 | #define AXP20X_VBUS_MON_VBUS_VALID BIT(3) | 53 | #define AXP20X_VBUS_MON_VBUS_VALID BIT(3) |
48 | 54 | ||
55 | /* | ||
56 | * Note do not raise the debounce time, we must report Vusb high within | ||
57 | * 100ms otherwise we get Vbus errors in musb. | ||
58 | */ | ||
59 | #define DEBOUNCE_TIME msecs_to_jiffies(50) | ||
60 | |||
49 | struct axp20x_usb_power { | 61 | struct axp20x_usb_power { |
50 | struct device_node *np; | 62 | struct device_node *np; |
51 | struct regmap *regmap; | 63 | struct regmap *regmap; |
@@ -53,6 +65,8 @@ struct axp20x_usb_power { | |||
53 | enum axp20x_variants axp20x_id; | 65 | enum axp20x_variants axp20x_id; |
54 | struct iio_channel *vbus_v; | 66 | struct iio_channel *vbus_v; |
55 | struct iio_channel *vbus_i; | 67 | struct iio_channel *vbus_i; |
68 | struct delayed_work vbus_detect; | ||
69 | unsigned int old_status; | ||
56 | }; | 70 | }; |
57 | 71 | ||
58 | static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) | 72 | static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) |
@@ -64,6 +78,89 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) | |||
64 | return IRQ_HANDLED; | 78 | return IRQ_HANDLED; |
65 | } | 79 | } |
66 | 80 | ||
81 | static void axp20x_usb_power_poll_vbus(struct work_struct *work) | ||
82 | { | ||
83 | struct axp20x_usb_power *power = | ||
84 | container_of(work, struct axp20x_usb_power, vbus_detect.work); | ||
85 | unsigned int val; | ||
86 | int ret; | ||
87 | |||
88 | ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val); | ||
89 | if (ret) | ||
90 | goto out; | ||
91 | |||
92 | val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED); | ||
93 | if (val != power->old_status) | ||
94 | power_supply_changed(power->supply); | ||
95 | |||
96 | power->old_status = val; | ||
97 | |||
98 | out: | ||
99 | mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME); | ||
100 | } | ||
101 | |||
102 | static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) | ||
103 | { | ||
104 | if (power->axp20x_id >= AXP221_ID) | ||
105 | return true; | ||
106 | |||
107 | return false; | ||
108 | } | ||
109 | |||
110 | static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val) | ||
111 | { | ||
112 | unsigned int v; | ||
113 | int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); | ||
114 | |||
115 | if (ret) | ||
116 | return ret; | ||
117 | |||
118 | switch (v & AXP20X_VBUS_CLIMIT_MASK) { | ||
119 | case AXP20X_VBUS_CLIMIT_100mA: | ||
120 | if (power->axp20x_id == AXP221_ID) | ||
121 | *val = -1; /* No 100mA limit */ | ||
122 | else | ||
123 | *val = 100000; | ||
124 | break; | ||
125 | case AXP20X_VBUS_CLIMIT_500mA: | ||
126 | *val = 500000; | ||
127 | break; | ||
128 | case AXP20X_VBUS_CLIMIT_900mA: | ||
129 | *val = 900000; | ||
130 | break; | ||
131 | case AXP20X_VBUS_CLIMIT_NONE: | ||
132 | *val = -1; | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int axp813_get_current_max(struct axp20x_usb_power *power, int *val) | ||
140 | { | ||
141 | unsigned int v; | ||
142 | int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); | ||
143 | |||
144 | if (ret) | ||
145 | return ret; | ||
146 | |||
147 | switch (v & AXP20X_VBUS_CLIMIT_MASK) { | ||
148 | case AXP813_VBUS_CLIMIT_900mA: | ||
149 | *val = 900000; | ||
150 | break; | ||
151 | case AXP813_VBUS_CLIMIT_1500mA: | ||
152 | *val = 1500000; | ||
153 | break; | ||
154 | case AXP813_VBUS_CLIMIT_2000mA: | ||
155 | *val = 2000000; | ||
156 | break; | ||
157 | case AXP813_VBUS_CLIMIT_2500mA: | ||
158 | *val = 2500000; | ||
159 | break; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
67 | static int axp20x_usb_power_get_property(struct power_supply *psy, | 164 | static int axp20x_usb_power_get_property(struct power_supply *psy, |
68 | enum power_supply_property psp, union power_supply_propval *val) | 165 | enum power_supply_property psp, union power_supply_propval *val) |
69 | { | 166 | { |
@@ -102,28 +199,9 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, | |||
102 | val->intval = ret * 1700; /* 1 step = 1.7 mV */ | 199 | val->intval = ret * 1700; /* 1 step = 1.7 mV */ |
103 | return 0; | 200 | return 0; |
104 | case POWER_SUPPLY_PROP_CURRENT_MAX: | 201 | case POWER_SUPPLY_PROP_CURRENT_MAX: |
105 | ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); | 202 | if (power->axp20x_id == AXP813_ID) |
106 | if (ret) | 203 | return axp813_get_current_max(power, &val->intval); |
107 | return ret; | 204 | return axp20x_get_current_max(power, &val->intval); |
108 | |||
109 | switch (v & AXP20X_VBUS_CLIMIT_MASK) { | ||
110 | case AXP20X_VBUC_CLIMIT_100mA: | ||
111 | if (power->axp20x_id == AXP221_ID) | ||
112 | val->intval = -1; /* No 100mA limit */ | ||
113 | else | ||
114 | val->intval = 100000; | ||
115 | break; | ||
116 | case AXP20X_VBUC_CLIMIT_500mA: | ||
117 | val->intval = 500000; | ||
118 | break; | ||
119 | case AXP20X_VBUC_CLIMIT_900mA: | ||
120 | val->intval = 900000; | ||
121 | break; | ||
122 | case AXP20X_VBUC_CLIMIT_NONE: | ||
123 | val->intval = -1; | ||
124 | break; | ||
125 | } | ||
126 | return 0; | ||
127 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 205 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
128 | if (IS_ENABLED(CONFIG_AXP20X_ADC)) { | 206 | if (IS_ENABLED(CONFIG_AXP20X_ADC)) { |
129 | ret = iio_read_channel_processed(power->vbus_i, | 207 | ret = iio_read_channel_processed(power->vbus_i, |
@@ -214,6 +292,31 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, | |||
214 | return -EINVAL; | 292 | return -EINVAL; |
215 | } | 293 | } |
216 | 294 | ||
295 | static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power, | ||
296 | int intval) | ||
297 | { | ||
298 | int val; | ||
299 | |||
300 | switch (intval) { | ||
301 | case 900000: | ||
302 | return regmap_update_bits(power->regmap, | ||
303 | AXP20X_VBUS_IPSOUT_MGMT, | ||
304 | AXP20X_VBUS_CLIMIT_MASK, | ||
305 | AXP813_VBUS_CLIMIT_900mA); | ||
306 | case 1500000: | ||
307 | case 2000000: | ||
308 | case 2500000: | ||
309 | val = (intval - 1000000) / 500000; | ||
310 | return regmap_update_bits(power->regmap, | ||
311 | AXP20X_VBUS_IPSOUT_MGMT, | ||
312 | AXP20X_VBUS_CLIMIT_MASK, val); | ||
313 | default: | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | return -EINVAL; | ||
318 | } | ||
319 | |||
217 | static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, | 320 | static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, |
218 | int intval) | 321 | int intval) |
219 | { | 322 | { |
@@ -248,6 +351,9 @@ static int axp20x_usb_power_set_property(struct power_supply *psy, | |||
248 | return axp20x_usb_power_set_voltage_min(power, val->intval); | 351 | return axp20x_usb_power_set_voltage_min(power, val->intval); |
249 | 352 | ||
250 | case POWER_SUPPLY_PROP_CURRENT_MAX: | 353 | case POWER_SUPPLY_PROP_CURRENT_MAX: |
354 | if (power->axp20x_id == AXP813_ID) | ||
355 | return axp813_usb_power_set_current_max(power, | ||
356 | val->intval); | ||
251 | return axp20x_usb_power_set_current_max(power, val->intval); | 357 | return axp20x_usb_power_set_current_max(power, val->intval); |
252 | 358 | ||
253 | default: | 359 | default: |
@@ -357,6 +463,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) | |||
357 | if (!power) | 463 | if (!power) |
358 | return -ENOMEM; | 464 | return -ENOMEM; |
359 | 465 | ||
466 | platform_set_drvdata(pdev, power); | ||
360 | power->axp20x_id = (enum axp20x_variants)of_device_get_match_data( | 467 | power->axp20x_id = (enum axp20x_variants)of_device_get_match_data( |
361 | &pdev->dev); | 468 | &pdev->dev); |
362 | 469 | ||
@@ -382,7 +489,8 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) | |||
382 | usb_power_desc = &axp20x_usb_power_desc; | 489 | usb_power_desc = &axp20x_usb_power_desc; |
383 | irq_names = axp20x_irq_names; | 490 | irq_names = axp20x_irq_names; |
384 | } else if (power->axp20x_id == AXP221_ID || | 491 | } else if (power->axp20x_id == AXP221_ID || |
385 | power->axp20x_id == AXP223_ID) { | 492 | power->axp20x_id == AXP223_ID || |
493 | power->axp20x_id == AXP813_ID) { | ||
386 | usb_power_desc = &axp22x_usb_power_desc; | 494 | usb_power_desc = &axp22x_usb_power_desc; |
387 | irq_names = axp22x_irq_names; | 495 | irq_names = axp22x_irq_names; |
388 | } else { | 496 | } else { |
@@ -415,6 +523,19 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) | |||
415 | irq_names[i], ret); | 523 | irq_names[i], ret); |
416 | } | 524 | } |
417 | 525 | ||
526 | INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus); | ||
527 | if (axp20x_usb_vbus_needs_polling(power)) | ||
528 | queue_delayed_work(system_wq, &power->vbus_detect, 0); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int axp20x_usb_power_remove(struct platform_device *pdev) | ||
534 | { | ||
535 | struct axp20x_usb_power *power = platform_get_drvdata(pdev); | ||
536 | |||
537 | cancel_delayed_work_sync(&power->vbus_detect); | ||
538 | |||
418 | return 0; | 539 | return 0; |
419 | } | 540 | } |
420 | 541 | ||
@@ -428,12 +549,16 @@ static const struct of_device_id axp20x_usb_power_match[] = { | |||
428 | }, { | 549 | }, { |
429 | .compatible = "x-powers,axp223-usb-power-supply", | 550 | .compatible = "x-powers,axp223-usb-power-supply", |
430 | .data = (void *)AXP223_ID, | 551 | .data = (void *)AXP223_ID, |
552 | }, { | ||
553 | .compatible = "x-powers,axp813-usb-power-supply", | ||
554 | .data = (void *)AXP813_ID, | ||
431 | }, { /* sentinel */ } | 555 | }, { /* sentinel */ } |
432 | }; | 556 | }; |
433 | MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); | 557 | MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); |
434 | 558 | ||
435 | static struct platform_driver axp20x_usb_power_driver = { | 559 | static struct platform_driver axp20x_usb_power_driver = { |
436 | .probe = axp20x_usb_power_probe, | 560 | .probe = axp20x_usb_power_probe, |
561 | .remove = axp20x_usb_power_remove, | ||
437 | .driver = { | 562 | .driver = { |
438 | .name = DRVNAME, | 563 | .name = DRVNAME, |
439 | .of_match_table = axp20x_usb_power_match, | 564 | .of_match_table = axp20x_usb_power_match, |
diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index f8c6da9277b3..00b961890a38 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c | |||
@@ -833,6 +833,10 @@ static int axp288_charger_probe(struct platform_device *pdev) | |||
833 | /* Register charger interrupts */ | 833 | /* Register charger interrupts */ |
834 | for (i = 0; i < CHRG_INTR_END; i++) { | 834 | for (i = 0; i < CHRG_INTR_END; i++) { |
835 | pirq = platform_get_irq(info->pdev, i); | 835 | pirq = platform_get_irq(info->pdev, i); |
836 | if (pirq < 0) { | ||
837 | dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pirq); | ||
838 | return pirq; | ||
839 | } | ||
836 | info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); | 840 | info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); |
837 | if (info->irq[i] < 0) { | 841 | if (info->irq[i] < 0) { |
838 | dev_warn(&info->pdev->dev, | 842 | dev_warn(&info->pdev->dev, |
diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 9ff2461820d8..368281bc0d2b 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c | |||
@@ -686,6 +686,26 @@ intr_failed: | |||
686 | */ | 686 | */ |
687 | static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { | 687 | static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { |
688 | { | 688 | { |
689 | /* ACEPC T8 Cherry Trail Z8350 mini PC */ | ||
690 | .matches = { | ||
691 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), | ||
692 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), | ||
693 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "T8"), | ||
694 | /* also match on somewhat unique bios-version */ | ||
695 | DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"), | ||
696 | }, | ||
697 | }, | ||
698 | { | ||
699 | /* ACEPC T11 Cherry Trail Z8350 mini PC */ | ||
700 | .matches = { | ||
701 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), | ||
702 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), | ||
703 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "T11"), | ||
704 | /* also match on somewhat unique bios-version */ | ||
705 | DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"), | ||
706 | }, | ||
707 | }, | ||
708 | { | ||
689 | /* Intel Cherry Trail Compute Stick, Windows version */ | 709 | /* Intel Cherry Trail Compute Stick, Windows version */ |
690 | .matches = { | 710 | .matches = { |
691 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), | 711 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), |
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 29b3a4056865..195c18c2f426 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c | |||
@@ -1612,7 +1612,8 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) | |||
1612 | di->charge_design_full = bq27xxx_battery_read_dcap(di); | 1612 | di->charge_design_full = bq27xxx_battery_read_dcap(di); |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | if (di->cache.capacity != cache.capacity) | 1615 | if ((di->cache.capacity != cache.capacity) || |
1616 | (di->cache.flags != cache.flags)) | ||
1616 | power_supply_changed(di->bat); | 1617 | power_supply_changed(di->bat); |
1617 | 1618 | ||
1618 | if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) | 1619 | if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) |
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 2e8db5e6de0b..a6900aa0d2ed 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c | |||
@@ -1987,6 +1987,9 @@ static struct platform_driver charger_manager_driver = { | |||
1987 | static int __init charger_manager_init(void) | 1987 | static int __init charger_manager_init(void) |
1988 | { | 1988 | { |
1989 | cm_wq = create_freezable_workqueue("charger_manager"); | 1989 | cm_wq = create_freezable_workqueue("charger_manager"); |
1990 | if (unlikely(!cm_wq)) | ||
1991 | return -ENOMEM; | ||
1992 | |||
1990 | INIT_DELAYED_WORK(&cm_monitor_work, cm_monitor_poller); | 1993 | INIT_DELAYED_WORK(&cm_monitor_work, cm_monitor_poller); |
1991 | 1994 | ||
1992 | return platform_driver_register(&charger_manager_driver); | 1995 | return platform_driver_register(&charger_manager_driver); |
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 6887870ba32c..61d6447d1966 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c | |||
@@ -82,9 +82,9 @@ struct cpcap_battery_config { | |||
82 | }; | 82 | }; |
83 | 83 | ||
84 | struct cpcap_coulomb_counter_data { | 84 | struct cpcap_coulomb_counter_data { |
85 | s32 sample; /* 24-bits */ | 85 | s32 sample; /* 24 or 32 bits */ |
86 | s32 accumulator; | 86 | s32 accumulator; |
87 | s16 offset; /* 10-bits */ | 87 | s16 offset; /* 9 bits */ |
88 | }; | 88 | }; |
89 | 89 | ||
90 | enum cpcap_battery_state { | 90 | enum cpcap_battery_state { |
@@ -213,7 +213,7 @@ static int cpcap_battery_get_current(struct cpcap_battery_ddata *ddata) | |||
213 | * TI or ST coulomb counter in the PMIC. | 213 | * TI or ST coulomb counter in the PMIC. |
214 | */ | 214 | */ |
215 | static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata, | 215 | static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata, |
216 | u32 sample, s32 accumulator, | 216 | s32 sample, s32 accumulator, |
217 | s16 offset, u32 divider) | 217 | s16 offset, u32 divider) |
218 | { | 218 | { |
219 | s64 acc; | 219 | s64 acc; |
@@ -224,9 +224,6 @@ static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata, | |||
224 | if (!divider) | 224 | if (!divider) |
225 | return 0; | 225 | return 0; |
226 | 226 | ||
227 | sample &= 0xffffff; /* 24-bits, unsigned */ | ||
228 | offset &= 0x7ff; /* 10-bits, signed */ | ||
229 | |||
230 | switch (ddata->vendor) { | 227 | switch (ddata->vendor) { |
231 | case CPCAP_VENDOR_ST: | 228 | case CPCAP_VENDOR_ST: |
232 | cc_lsb = 95374; /* μAms per LSB */ | 229 | cc_lsb = 95374; /* μAms per LSB */ |
@@ -259,7 +256,7 @@ static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata, | |||
259 | 256 | ||
260 | /* 3600000μAms = 1μAh */ | 257 | /* 3600000μAms = 1μAh */ |
261 | static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata, | 258 | static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata, |
262 | u32 sample, s32 accumulator, | 259 | s32 sample, s32 accumulator, |
263 | s16 offset) | 260 | s16 offset) |
264 | { | 261 | { |
265 | return cpcap_battery_cc_raw_div(ddata, sample, | 262 | return cpcap_battery_cc_raw_div(ddata, sample, |
@@ -268,7 +265,7 @@ static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata, | |||
268 | } | 265 | } |
269 | 266 | ||
270 | static int cpcap_battery_cc_to_ua(struct cpcap_battery_ddata *ddata, | 267 | static int cpcap_battery_cc_to_ua(struct cpcap_battery_ddata *ddata, |
271 | u32 sample, s32 accumulator, | 268 | s32 sample, s32 accumulator, |
272 | s16 offset) | 269 | s16 offset) |
273 | { | 270 | { |
274 | return cpcap_battery_cc_raw_div(ddata, sample, | 271 | return cpcap_battery_cc_raw_div(ddata, sample, |
@@ -312,17 +309,19 @@ cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata, | |||
312 | /* Sample value CPCAP_REG_CCS1 & 2 */ | 309 | /* Sample value CPCAP_REG_CCS1 & 2 */ |
313 | ccd->sample = (buf[1] & 0x0fff) << 16; | 310 | ccd->sample = (buf[1] & 0x0fff) << 16; |
314 | ccd->sample |= buf[0]; | 311 | ccd->sample |= buf[0]; |
312 | if (ddata->vendor == CPCAP_VENDOR_TI) | ||
313 | ccd->sample = sign_extend32(24, ccd->sample); | ||
315 | 314 | ||
316 | /* Accumulator value CPCAP_REG_CCA1 & 2 */ | 315 | /* Accumulator value CPCAP_REG_CCA1 & 2 */ |
317 | ccd->accumulator = ((s16)buf[3]) << 16; | 316 | ccd->accumulator = ((s16)buf[3]) << 16; |
318 | ccd->accumulator |= buf[2]; | 317 | ccd->accumulator |= buf[2]; |
319 | 318 | ||
320 | /* Offset value CPCAP_REG_CCO */ | 319 | /* |
321 | ccd->offset = buf[5]; | 320 | * Coulomb counter calibration offset is CPCAP_REG_CCM, |
322 | 321 | * REG_CCO seems unused | |
323 | /* Adjust offset based on mode value CPCAP_REG_CCM? */ | 322 | */ |
324 | if (buf[4] >= 0x200) | 323 | ccd->offset = buf[4]; |
325 | ccd->offset |= 0xfc00; | 324 | ccd->offset = sign_extend32(ccd->offset, 9); |
326 | 325 | ||
327 | return cpcap_battery_cc_to_uah(ddata, | 326 | return cpcap_battery_cc_to_uah(ddata, |
328 | ccd->sample, | 327 | ccd->sample, |
@@ -477,11 +476,11 @@ static int cpcap_battery_get_property(struct power_supply *psy, | |||
477 | val->intval = ddata->config.info.voltage_min_design; | 476 | val->intval = ddata->config.info.voltage_min_design; |
478 | break; | 477 | break; |
479 | case POWER_SUPPLY_PROP_CURRENT_AVG: | 478 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
480 | if (cached) { | 479 | sample = latest->cc.sample - previous->cc.sample; |
480 | if (!sample) { | ||
481 | val->intval = cpcap_battery_cc_get_avg_current(ddata); | 481 | val->intval = cpcap_battery_cc_get_avg_current(ddata); |
482 | break; | 482 | break; |
483 | } | 483 | } |
484 | sample = latest->cc.sample - previous->cc.sample; | ||
485 | accumulator = latest->cc.accumulator - previous->cc.accumulator; | 484 | accumulator = latest->cc.accumulator - previous->cc.accumulator; |
486 | val->intval = cpcap_battery_cc_to_ua(ddata, sample, | 485 | val->intval = cpcap_battery_cc_to_ua(ddata, sample, |
487 | accumulator, | 486 | accumulator, |
@@ -498,13 +497,13 @@ static int cpcap_battery_get_property(struct power_supply *psy, | |||
498 | val->intval = div64_s64(tmp, 100); | 497 | val->intval = div64_s64(tmp, 100); |
499 | break; | 498 | break; |
500 | case POWER_SUPPLY_PROP_POWER_AVG: | 499 | case POWER_SUPPLY_PROP_POWER_AVG: |
501 | if (cached) { | 500 | sample = latest->cc.sample - previous->cc.sample; |
501 | if (!sample) { | ||
502 | tmp = cpcap_battery_cc_get_avg_current(ddata); | 502 | tmp = cpcap_battery_cc_get_avg_current(ddata); |
503 | tmp *= (latest->voltage / 10000); | 503 | tmp *= (latest->voltage / 10000); |
504 | val->intval = div64_s64(tmp, 100); | 504 | val->intval = div64_s64(tmp, 100); |
505 | break; | 505 | break; |
506 | } | 506 | } |
507 | sample = latest->cc.sample - previous->cc.sample; | ||
508 | accumulator = latest->cc.accumulator - previous->cc.accumulator; | 507 | accumulator = latest->cc.accumulator - previous->cc.accumulator; |
509 | tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator, | 508 | tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator, |
510 | latest->cc.offset); | 509 | latest->cc.offset); |
@@ -562,11 +561,11 @@ static irqreturn_t cpcap_battery_irq_thread(int irq, void *data) | |||
562 | 561 | ||
563 | switch (d->action) { | 562 | switch (d->action) { |
564 | case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW: | 563 | case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW: |
565 | if (latest->counter_uah >= 0) | 564 | if (latest->current_ua >= 0) |
566 | dev_warn(ddata->dev, "Battery low at 3.3V!\n"); | 565 | dev_warn(ddata->dev, "Battery low at 3.3V!\n"); |
567 | break; | 566 | break; |
568 | case CPCAP_BATTERY_IRQ_ACTION_POWEROFF: | 567 | case CPCAP_BATTERY_IRQ_ACTION_POWEROFF: |
569 | if (latest->counter_uah >= 0) { | 568 | if (latest->current_ua >= 0) { |
570 | dev_emerg(ddata->dev, | 569 | dev_emerg(ddata->dev, |
571 | "Battery empty at 3.1V, powering off\n"); | 570 | "Battery empty at 3.1V, powering off\n"); |
572 | orderly_poweroff(true); | 571 | orderly_poweroff(true); |
@@ -670,8 +669,9 @@ static int cpcap_battery_init_iio(struct cpcap_battery_ddata *ddata) | |||
670 | return 0; | 669 | return 0; |
671 | 670 | ||
672 | out_err: | 671 | out_err: |
673 | dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", | 672 | if (error != -EPROBE_DEFER) |
674 | error); | 673 | dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", |
674 | error); | ||
675 | 675 | ||
676 | return error; | 676 | return error; |
677 | } | 677 | } |
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index c3ed7b476676..b4781b5d1e10 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c | |||
@@ -574,8 +574,9 @@ static int cpcap_charger_init_iio(struct cpcap_charger_ddata *ddata) | |||
574 | return 0; | 574 | return 0; |
575 | 575 | ||
576 | out_err: | 576 | out_err: |
577 | dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", | 577 | if (error != -EPROBE_DEFER) |
578 | error); | 578 | dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", |
579 | error); | ||
579 | 580 | ||
580 | return error; | 581 | return error; |
581 | } | 582 | } |
diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c index 7e4f11d5a230..f99e8f1eef23 100644 --- a/drivers/power/supply/gpio-charger.c +++ b/drivers/power/supply/gpio-charger.c | |||
@@ -29,11 +29,13 @@ | |||
29 | 29 | ||
30 | struct gpio_charger { | 30 | struct gpio_charger { |
31 | unsigned int irq; | 31 | unsigned int irq; |
32 | unsigned int charge_status_irq; | ||
32 | bool wakeup_enabled; | 33 | bool wakeup_enabled; |
33 | 34 | ||
34 | struct power_supply *charger; | 35 | struct power_supply *charger; |
35 | struct power_supply_desc charger_desc; | 36 | struct power_supply_desc charger_desc; |
36 | struct gpio_desc *gpiod; | 37 | struct gpio_desc *gpiod; |
38 | struct gpio_desc *charge_status; | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | static irqreturn_t gpio_charger_irq(int irq, void *devid) | 41 | static irqreturn_t gpio_charger_irq(int irq, void *devid) |
@@ -59,6 +61,12 @@ static int gpio_charger_get_property(struct power_supply *psy, | |||
59 | case POWER_SUPPLY_PROP_ONLINE: | 61 | case POWER_SUPPLY_PROP_ONLINE: |
60 | val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); | 62 | val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); |
61 | break; | 63 | break; |
64 | case POWER_SUPPLY_PROP_STATUS: | ||
65 | if (gpiod_get_value_cansleep(gpio_charger->charge_status)) | ||
66 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
67 | else | ||
68 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
69 | break; | ||
62 | default: | 70 | default: |
63 | return -EINVAL; | 71 | return -EINVAL; |
64 | } | 72 | } |
@@ -93,8 +101,29 @@ static enum power_supply_type gpio_charger_get_type(struct device *dev) | |||
93 | return POWER_SUPPLY_TYPE_UNKNOWN; | 101 | return POWER_SUPPLY_TYPE_UNKNOWN; |
94 | } | 102 | } |
95 | 103 | ||
104 | static int gpio_charger_get_irq(struct device *dev, void *dev_id, | ||
105 | struct gpio_desc *gpio) | ||
106 | { | ||
107 | int ret, irq = gpiod_to_irq(gpio); | ||
108 | |||
109 | if (irq > 0) { | ||
110 | ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq, | ||
111 | IRQF_TRIGGER_RISING | | ||
112 | IRQF_TRIGGER_FALLING, | ||
113 | dev_name(dev), | ||
114 | dev_id); | ||
115 | if (ret < 0) { | ||
116 | dev_warn(dev, "Failed to request irq: %d\n", ret); | ||
117 | irq = 0; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | return irq; | ||
122 | } | ||
123 | |||
96 | static enum power_supply_property gpio_charger_properties[] = { | 124 | static enum power_supply_property gpio_charger_properties[] = { |
97 | POWER_SUPPLY_PROP_ONLINE, | 125 | POWER_SUPPLY_PROP_ONLINE, |
126 | POWER_SUPPLY_PROP_STATUS /* Must always be last in the array. */ | ||
98 | }; | 127 | }; |
99 | 128 | ||
100 | static int gpio_charger_probe(struct platform_device *pdev) | 129 | static int gpio_charger_probe(struct platform_device *pdev) |
@@ -104,8 +133,10 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
104 | struct power_supply_config psy_cfg = {}; | 133 | struct power_supply_config psy_cfg = {}; |
105 | struct gpio_charger *gpio_charger; | 134 | struct gpio_charger *gpio_charger; |
106 | struct power_supply_desc *charger_desc; | 135 | struct power_supply_desc *charger_desc; |
136 | struct gpio_desc *charge_status; | ||
137 | int charge_status_irq; | ||
107 | unsigned long flags; | 138 | unsigned long flags; |
108 | int irq, ret; | 139 | int ret; |
109 | 140 | ||
110 | if (!pdata && !dev->of_node) { | 141 | if (!pdata && !dev->of_node) { |
111 | dev_err(dev, "No platform data\n"); | 142 | dev_err(dev, "No platform data\n"); |
@@ -151,9 +182,17 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
151 | return PTR_ERR(gpio_charger->gpiod); | 182 | return PTR_ERR(gpio_charger->gpiod); |
152 | } | 183 | } |
153 | 184 | ||
185 | charge_status = devm_gpiod_get_optional(dev, "charge-status", GPIOD_IN); | ||
186 | gpio_charger->charge_status = charge_status; | ||
187 | if (IS_ERR(gpio_charger->charge_status)) | ||
188 | return PTR_ERR(gpio_charger->charge_status); | ||
189 | |||
154 | charger_desc = &gpio_charger->charger_desc; | 190 | charger_desc = &gpio_charger->charger_desc; |
155 | charger_desc->properties = gpio_charger_properties; | 191 | charger_desc->properties = gpio_charger_properties; |
156 | charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties); | 192 | charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties); |
193 | /* Remove POWER_SUPPLY_PROP_STATUS from the supported properties. */ | ||
194 | if (!gpio_charger->charge_status) | ||
195 | charger_desc->num_properties -= 1; | ||
157 | charger_desc->get_property = gpio_charger_get_property; | 196 | charger_desc->get_property = gpio_charger_get_property; |
158 | 197 | ||
159 | psy_cfg.of_node = dev->of_node; | 198 | psy_cfg.of_node = dev->of_node; |
@@ -180,16 +219,12 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
180 | return ret; | 219 | return ret; |
181 | } | 220 | } |
182 | 221 | ||
183 | irq = gpiod_to_irq(gpio_charger->gpiod); | 222 | gpio_charger->irq = gpio_charger_get_irq(dev, gpio_charger->charger, |
184 | if (irq > 0) { | 223 | gpio_charger->gpiod); |
185 | ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq, | 224 | |
186 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 225 | charge_status_irq = gpio_charger_get_irq(dev, gpio_charger->charger, |
187 | dev_name(dev), gpio_charger->charger); | 226 | gpio_charger->charge_status); |
188 | if (ret < 0) | 227 | gpio_charger->charge_status_irq = charge_status_irq; |
189 | dev_warn(dev, "Failed to request irq: %d\n", ret); | ||
190 | else | ||
191 | gpio_charger->irq = irq; | ||
192 | } | ||
193 | 228 | ||
194 | platform_set_drvdata(pdev, gpio_charger); | 229 | platform_set_drvdata(pdev, gpio_charger); |
195 | 230 | ||
diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c new file mode 100644 index 000000000000..35816d4b3012 --- /dev/null +++ b/drivers/power/supply/ingenic-battery.c | |||
@@ -0,0 +1,184 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Battery driver for the Ingenic JZ47xx SoCs | ||
4 | * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu> | ||
5 | * | ||
6 | * based on drivers/power/supply/jz4740-battery.c | ||
7 | */ | ||
8 | |||
9 | #include <linux/iio/consumer.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/power_supply.h> | ||
14 | #include <linux/property.h> | ||
15 | |||
16 | struct ingenic_battery { | ||
17 | struct device *dev; | ||
18 | struct iio_channel *channel; | ||
19 | struct power_supply_desc desc; | ||
20 | struct power_supply *battery; | ||
21 | struct power_supply_battery_info info; | ||
22 | }; | ||
23 | |||
24 | static int ingenic_battery_get_property(struct power_supply *psy, | ||
25 | enum power_supply_property psp, | ||
26 | union power_supply_propval *val) | ||
27 | { | ||
28 | struct ingenic_battery *bat = power_supply_get_drvdata(psy); | ||
29 | struct power_supply_battery_info *info = &bat->info; | ||
30 | int ret; | ||
31 | |||
32 | switch (psp) { | ||
33 | case POWER_SUPPLY_PROP_HEALTH: | ||
34 | ret = iio_read_channel_processed(bat->channel, &val->intval); | ||
35 | val->intval *= 1000; | ||
36 | if (val->intval < info->voltage_min_design_uv) | ||
37 | val->intval = POWER_SUPPLY_HEALTH_DEAD; | ||
38 | else if (val->intval > info->voltage_max_design_uv) | ||
39 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | ||
40 | else | ||
41 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
42 | return ret; | ||
43 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
44 | ret = iio_read_channel_processed(bat->channel, &val->intval); | ||
45 | val->intval *= 1000; | ||
46 | return ret; | ||
47 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
48 | val->intval = info->voltage_min_design_uv; | ||
49 | return 0; | ||
50 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
51 | val->intval = info->voltage_max_design_uv; | ||
52 | return 0; | ||
53 | default: | ||
54 | return -EINVAL; | ||
55 | }; | ||
56 | } | ||
57 | |||
58 | /* Set the most appropriate IIO channel voltage reference scale | ||
59 | * based on the battery's max voltage. | ||
60 | */ | ||
61 | static int ingenic_battery_set_scale(struct ingenic_battery *bat) | ||
62 | { | ||
63 | const int *scale_raw; | ||
64 | int scale_len, scale_type, best_idx = -1, best_mV, max_raw, i, ret; | ||
65 | u64 max_mV; | ||
66 | |||
67 | ret = iio_read_max_channel_raw(bat->channel, &max_raw); | ||
68 | if (ret) { | ||
69 | dev_err(bat->dev, "Unable to read max raw channel value\n"); | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | ret = iio_read_avail_channel_attribute(bat->channel, &scale_raw, | ||
74 | &scale_type, &scale_len, | ||
75 | IIO_CHAN_INFO_SCALE); | ||
76 | if (ret < 0) { | ||
77 | dev_err(bat->dev, "Unable to read channel avail scale\n"); | ||
78 | return ret; | ||
79 | } | ||
80 | if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) | ||
81 | return -EINVAL; | ||
82 | |||
83 | max_mV = bat->info.voltage_max_design_uv / 1000; | ||
84 | |||
85 | for (i = 0; i < scale_len; i += 2) { | ||
86 | u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1]; | ||
87 | |||
88 | if (scale_mV < max_mV) | ||
89 | continue; | ||
90 | |||
91 | if (best_idx >= 0 && scale_mV > best_mV) | ||
92 | continue; | ||
93 | |||
94 | best_mV = scale_mV; | ||
95 | best_idx = i; | ||
96 | } | ||
97 | |||
98 | if (best_idx < 0) { | ||
99 | dev_err(bat->dev, "Unable to find matching voltage scale\n"); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | return iio_write_channel_attribute(bat->channel, | ||
104 | scale_raw[best_idx], | ||
105 | scale_raw[best_idx + 1], | ||
106 | IIO_CHAN_INFO_SCALE); | ||
107 | } | ||
108 | |||
109 | static enum power_supply_property ingenic_battery_properties[] = { | ||
110 | POWER_SUPPLY_PROP_HEALTH, | ||
111 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
112 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
113 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
114 | }; | ||
115 | |||
116 | static int ingenic_battery_probe(struct platform_device *pdev) | ||
117 | { | ||
118 | struct device *dev = &pdev->dev; | ||
119 | struct ingenic_battery *bat; | ||
120 | struct power_supply_config psy_cfg = {}; | ||
121 | struct power_supply_desc *desc; | ||
122 | int ret; | ||
123 | |||
124 | bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL); | ||
125 | if (!bat) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | bat->dev = dev; | ||
129 | bat->channel = devm_iio_channel_get(dev, "battery"); | ||
130 | if (IS_ERR(bat->channel)) | ||
131 | return PTR_ERR(bat->channel); | ||
132 | |||
133 | desc = &bat->desc; | ||
134 | desc->name = "jz-battery"; | ||
135 | desc->type = POWER_SUPPLY_TYPE_BATTERY; | ||
136 | desc->properties = ingenic_battery_properties; | ||
137 | desc->num_properties = ARRAY_SIZE(ingenic_battery_properties); | ||
138 | desc->get_property = ingenic_battery_get_property; | ||
139 | psy_cfg.drv_data = bat; | ||
140 | psy_cfg.of_node = dev->of_node; | ||
141 | |||
142 | bat->battery = devm_power_supply_register(dev, desc, &psy_cfg); | ||
143 | if (IS_ERR(bat->battery)) { | ||
144 | dev_err(dev, "Unable to register battery\n"); | ||
145 | return PTR_ERR(bat->battery); | ||
146 | } | ||
147 | |||
148 | ret = power_supply_get_battery_info(bat->battery, &bat->info); | ||
149 | if (ret) { | ||
150 | dev_err(dev, "Unable to get battery info: %d\n", ret); | ||
151 | return ret; | ||
152 | } | ||
153 | if (bat->info.voltage_min_design_uv < 0) { | ||
154 | dev_err(dev, "Unable to get voltage min design\n"); | ||
155 | return bat->info.voltage_min_design_uv; | ||
156 | } | ||
157 | if (bat->info.voltage_max_design_uv < 0) { | ||
158 | dev_err(dev, "Unable to get voltage max design\n"); | ||
159 | return bat->info.voltage_max_design_uv; | ||
160 | } | ||
161 | |||
162 | return ingenic_battery_set_scale(bat); | ||
163 | } | ||
164 | |||
165 | #ifdef CONFIG_OF | ||
166 | static const struct of_device_id ingenic_battery_of_match[] = { | ||
167 | { .compatible = "ingenic,jz4740-battery", }, | ||
168 | { }, | ||
169 | }; | ||
170 | MODULE_DEVICE_TABLE(of, ingenic_battery_of_match); | ||
171 | #endif | ||
172 | |||
173 | static struct platform_driver ingenic_battery_driver = { | ||
174 | .driver = { | ||
175 | .name = "ingenic-battery", | ||
176 | .of_match_table = of_match_ptr(ingenic_battery_of_match), | ||
177 | }, | ||
178 | .probe = ingenic_battery_probe, | ||
179 | }; | ||
180 | module_platform_driver(ingenic_battery_driver); | ||
181 | |||
182 | MODULE_DESCRIPTION("Battery driver for Ingenic JZ47xx SoCs"); | ||
183 | MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); | ||
184 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/supply/ltc3651-charger.c b/drivers/power/supply/lt3651-charger.c index eea63ff211c4..8de500ffad95 100644 --- a/drivers/power/supply/ltc3651-charger.c +++ b/drivers/power/supply/lt3651-charger.c | |||
@@ -1,11 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
1 | /* | 2 | /* |
3 | * Driver for Analog Devices (Linear Technology) LT3651 charger IC. | ||
2 | * Copyright (C) 2017, Topic Embedded Products | 4 | * Copyright (C) 2017, Topic Embedded Products |
3 | * Driver for LTC3651 charger IC. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | 5 | */ |
10 | 6 | ||
11 | #include <linux/device.h> | 7 | #include <linux/device.h> |
@@ -19,7 +15,7 @@ | |||
19 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
20 | #include <linux/of.h> | 16 | #include <linux/of.h> |
21 | 17 | ||
22 | struct ltc3651_charger { | 18 | struct lt3651_charger { |
23 | struct power_supply *charger; | 19 | struct power_supply *charger; |
24 | struct power_supply_desc charger_desc; | 20 | struct power_supply_desc charger_desc; |
25 | struct gpio_desc *acpr_gpio; | 21 | struct gpio_desc *acpr_gpio; |
@@ -27,7 +23,7 @@ struct ltc3651_charger { | |||
27 | struct gpio_desc *chrg_gpio; | 23 | struct gpio_desc *chrg_gpio; |
28 | }; | 24 | }; |
29 | 25 | ||
30 | static irqreturn_t ltc3651_charger_irq(int irq, void *devid) | 26 | static irqreturn_t lt3651_charger_irq(int irq, void *devid) |
31 | { | 27 | { |
32 | struct power_supply *charger = devid; | 28 | struct power_supply *charger = devid; |
33 | 29 | ||
@@ -36,37 +32,37 @@ static irqreturn_t ltc3651_charger_irq(int irq, void *devid) | |||
36 | return IRQ_HANDLED; | 32 | return IRQ_HANDLED; |
37 | } | 33 | } |
38 | 34 | ||
39 | static inline struct ltc3651_charger *psy_to_ltc3651_charger( | 35 | static inline struct lt3651_charger *psy_to_lt3651_charger( |
40 | struct power_supply *psy) | 36 | struct power_supply *psy) |
41 | { | 37 | { |
42 | return power_supply_get_drvdata(psy); | 38 | return power_supply_get_drvdata(psy); |
43 | } | 39 | } |
44 | 40 | ||
45 | static int ltc3651_charger_get_property(struct power_supply *psy, | 41 | static int lt3651_charger_get_property(struct power_supply *psy, |
46 | enum power_supply_property psp, union power_supply_propval *val) | 42 | enum power_supply_property psp, union power_supply_propval *val) |
47 | { | 43 | { |
48 | struct ltc3651_charger *ltc3651_charger = psy_to_ltc3651_charger(psy); | 44 | struct lt3651_charger *lt3651_charger = psy_to_lt3651_charger(psy); |
49 | 45 | ||
50 | switch (psp) { | 46 | switch (psp) { |
51 | case POWER_SUPPLY_PROP_STATUS: | 47 | case POWER_SUPPLY_PROP_STATUS: |
52 | if (!ltc3651_charger->chrg_gpio) { | 48 | if (!lt3651_charger->chrg_gpio) { |
53 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | 49 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; |
54 | break; | 50 | break; |
55 | } | 51 | } |
56 | if (gpiod_get_value(ltc3651_charger->chrg_gpio)) | 52 | if (gpiod_get_value(lt3651_charger->chrg_gpio)) |
57 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | 53 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
58 | else | 54 | else |
59 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | 55 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; |
60 | break; | 56 | break; |
61 | case POWER_SUPPLY_PROP_ONLINE: | 57 | case POWER_SUPPLY_PROP_ONLINE: |
62 | val->intval = gpiod_get_value(ltc3651_charger->acpr_gpio); | 58 | val->intval = gpiod_get_value(lt3651_charger->acpr_gpio); |
63 | break; | 59 | break; |
64 | case POWER_SUPPLY_PROP_HEALTH: | 60 | case POWER_SUPPLY_PROP_HEALTH: |
65 | if (!ltc3651_charger->fault_gpio) { | 61 | if (!lt3651_charger->fault_gpio) { |
66 | val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; | 62 | val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; |
67 | break; | 63 | break; |
68 | } | 64 | } |
69 | if (!gpiod_get_value(ltc3651_charger->fault_gpio)) { | 65 | if (!gpiod_get_value(lt3651_charger->fault_gpio)) { |
70 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | 66 | val->intval = POWER_SUPPLY_HEALTH_GOOD; |
71 | break; | 67 | break; |
72 | } | 68 | } |
@@ -74,11 +70,11 @@ static int ltc3651_charger_get_property(struct power_supply *psy, | |||
74 | * If the fault pin is active, the chrg pin explains the type | 70 | * If the fault pin is active, the chrg pin explains the type |
75 | * of failure. | 71 | * of failure. |
76 | */ | 72 | */ |
77 | if (!ltc3651_charger->chrg_gpio) { | 73 | if (!lt3651_charger->chrg_gpio) { |
78 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | 74 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; |
79 | break; | 75 | break; |
80 | } | 76 | } |
81 | val->intval = gpiod_get_value(ltc3651_charger->chrg_gpio) ? | 77 | val->intval = gpiod_get_value(lt3651_charger->chrg_gpio) ? |
82 | POWER_SUPPLY_HEALTH_OVERHEAT : | 78 | POWER_SUPPLY_HEALTH_OVERHEAT : |
83 | POWER_SUPPLY_HEALTH_DEAD; | 79 | POWER_SUPPLY_HEALTH_DEAD; |
84 | break; | 80 | break; |
@@ -89,59 +85,59 @@ static int ltc3651_charger_get_property(struct power_supply *psy, | |||
89 | return 0; | 85 | return 0; |
90 | } | 86 | } |
91 | 87 | ||
92 | static enum power_supply_property ltc3651_charger_properties[] = { | 88 | static enum power_supply_property lt3651_charger_properties[] = { |
93 | POWER_SUPPLY_PROP_STATUS, | 89 | POWER_SUPPLY_PROP_STATUS, |
94 | POWER_SUPPLY_PROP_ONLINE, | 90 | POWER_SUPPLY_PROP_ONLINE, |
95 | POWER_SUPPLY_PROP_HEALTH, | 91 | POWER_SUPPLY_PROP_HEALTH, |
96 | }; | 92 | }; |
97 | 93 | ||
98 | static int ltc3651_charger_probe(struct platform_device *pdev) | 94 | static int lt3651_charger_probe(struct platform_device *pdev) |
99 | { | 95 | { |
100 | struct power_supply_config psy_cfg = {}; | 96 | struct power_supply_config psy_cfg = {}; |
101 | struct ltc3651_charger *ltc3651_charger; | 97 | struct lt3651_charger *lt3651_charger; |
102 | struct power_supply_desc *charger_desc; | 98 | struct power_supply_desc *charger_desc; |
103 | int ret; | 99 | int ret; |
104 | 100 | ||
105 | ltc3651_charger = devm_kzalloc(&pdev->dev, sizeof(*ltc3651_charger), | 101 | lt3651_charger = devm_kzalloc(&pdev->dev, sizeof(*lt3651_charger), |
106 | GFP_KERNEL); | 102 | GFP_KERNEL); |
107 | if (!ltc3651_charger) | 103 | if (!lt3651_charger) |
108 | return -ENOMEM; | 104 | return -ENOMEM; |
109 | 105 | ||
110 | ltc3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev, | 106 | lt3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev, |
111 | "lltc,acpr", GPIOD_IN); | 107 | "lltc,acpr", GPIOD_IN); |
112 | if (IS_ERR(ltc3651_charger->acpr_gpio)) { | 108 | if (IS_ERR(lt3651_charger->acpr_gpio)) { |
113 | ret = PTR_ERR(ltc3651_charger->acpr_gpio); | 109 | ret = PTR_ERR(lt3651_charger->acpr_gpio); |
114 | dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret); | 110 | dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret); |
115 | return ret; | 111 | return ret; |
116 | } | 112 | } |
117 | ltc3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev, | 113 | lt3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev, |
118 | "lltc,fault", GPIOD_IN); | 114 | "lltc,fault", GPIOD_IN); |
119 | if (IS_ERR(ltc3651_charger->fault_gpio)) { | 115 | if (IS_ERR(lt3651_charger->fault_gpio)) { |
120 | ret = PTR_ERR(ltc3651_charger->fault_gpio); | 116 | ret = PTR_ERR(lt3651_charger->fault_gpio); |
121 | dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret); | 117 | dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret); |
122 | return ret; | 118 | return ret; |
123 | } | 119 | } |
124 | ltc3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev, | 120 | lt3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev, |
125 | "lltc,chrg", GPIOD_IN); | 121 | "lltc,chrg", GPIOD_IN); |
126 | if (IS_ERR(ltc3651_charger->chrg_gpio)) { | 122 | if (IS_ERR(lt3651_charger->chrg_gpio)) { |
127 | ret = PTR_ERR(ltc3651_charger->chrg_gpio); | 123 | ret = PTR_ERR(lt3651_charger->chrg_gpio); |
128 | dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret); | 124 | dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret); |
129 | return ret; | 125 | return ret; |
130 | } | 126 | } |
131 | 127 | ||
132 | charger_desc = <c3651_charger->charger_desc; | 128 | charger_desc = <3651_charger->charger_desc; |
133 | charger_desc->name = pdev->dev.of_node->name; | 129 | charger_desc->name = pdev->dev.of_node->name; |
134 | charger_desc->type = POWER_SUPPLY_TYPE_MAINS; | 130 | charger_desc->type = POWER_SUPPLY_TYPE_MAINS; |
135 | charger_desc->properties = ltc3651_charger_properties; | 131 | charger_desc->properties = lt3651_charger_properties; |
136 | charger_desc->num_properties = ARRAY_SIZE(ltc3651_charger_properties); | 132 | charger_desc->num_properties = ARRAY_SIZE(lt3651_charger_properties); |
137 | charger_desc->get_property = ltc3651_charger_get_property; | 133 | charger_desc->get_property = lt3651_charger_get_property; |
138 | psy_cfg.of_node = pdev->dev.of_node; | 134 | psy_cfg.of_node = pdev->dev.of_node; |
139 | psy_cfg.drv_data = ltc3651_charger; | 135 | psy_cfg.drv_data = lt3651_charger; |
140 | 136 | ||
141 | ltc3651_charger->charger = devm_power_supply_register(&pdev->dev, | 137 | lt3651_charger->charger = devm_power_supply_register(&pdev->dev, |
142 | charger_desc, &psy_cfg); | 138 | charger_desc, &psy_cfg); |
143 | if (IS_ERR(ltc3651_charger->charger)) { | 139 | if (IS_ERR(lt3651_charger->charger)) { |
144 | ret = PTR_ERR(ltc3651_charger->charger); | 140 | ret = PTR_ERR(lt3651_charger->charger); |
145 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", | 141 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", |
146 | ret); | 142 | ret); |
147 | return ret; | 143 | return ret; |
@@ -152,59 +148,60 @@ static int ltc3651_charger_probe(struct platform_device *pdev) | |||
152 | * support IRQs on these pins, userspace will have to poll the sysfs | 148 | * support IRQs on these pins, userspace will have to poll the sysfs |
153 | * files manually. | 149 | * files manually. |
154 | */ | 150 | */ |
155 | if (ltc3651_charger->acpr_gpio) { | 151 | if (lt3651_charger->acpr_gpio) { |
156 | ret = gpiod_to_irq(ltc3651_charger->acpr_gpio); | 152 | ret = gpiod_to_irq(lt3651_charger->acpr_gpio); |
157 | if (ret >= 0) | 153 | if (ret >= 0) |
158 | ret = devm_request_any_context_irq(&pdev->dev, ret, | 154 | ret = devm_request_any_context_irq(&pdev->dev, ret, |
159 | ltc3651_charger_irq, | 155 | lt3651_charger_irq, |
160 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 156 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
161 | dev_name(&pdev->dev), ltc3651_charger->charger); | 157 | dev_name(&pdev->dev), lt3651_charger->charger); |
162 | if (ret < 0) | 158 | if (ret < 0) |
163 | dev_warn(&pdev->dev, "Failed to request acpr irq\n"); | 159 | dev_warn(&pdev->dev, "Failed to request acpr irq\n"); |
164 | } | 160 | } |
165 | if (ltc3651_charger->fault_gpio) { | 161 | if (lt3651_charger->fault_gpio) { |
166 | ret = gpiod_to_irq(ltc3651_charger->fault_gpio); | 162 | ret = gpiod_to_irq(lt3651_charger->fault_gpio); |
167 | if (ret >= 0) | 163 | if (ret >= 0) |
168 | ret = devm_request_any_context_irq(&pdev->dev, ret, | 164 | ret = devm_request_any_context_irq(&pdev->dev, ret, |
169 | ltc3651_charger_irq, | 165 | lt3651_charger_irq, |
170 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 166 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
171 | dev_name(&pdev->dev), ltc3651_charger->charger); | 167 | dev_name(&pdev->dev), lt3651_charger->charger); |
172 | if (ret < 0) | 168 | if (ret < 0) |
173 | dev_warn(&pdev->dev, "Failed to request fault irq\n"); | 169 | dev_warn(&pdev->dev, "Failed to request fault irq\n"); |
174 | } | 170 | } |
175 | if (ltc3651_charger->chrg_gpio) { | 171 | if (lt3651_charger->chrg_gpio) { |
176 | ret = gpiod_to_irq(ltc3651_charger->chrg_gpio); | 172 | ret = gpiod_to_irq(lt3651_charger->chrg_gpio); |
177 | if (ret >= 0) | 173 | if (ret >= 0) |
178 | ret = devm_request_any_context_irq(&pdev->dev, ret, | 174 | ret = devm_request_any_context_irq(&pdev->dev, ret, |
179 | ltc3651_charger_irq, | 175 | lt3651_charger_irq, |
180 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 176 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
181 | dev_name(&pdev->dev), ltc3651_charger->charger); | 177 | dev_name(&pdev->dev), lt3651_charger->charger); |
182 | if (ret < 0) | 178 | if (ret < 0) |
183 | dev_warn(&pdev->dev, "Failed to request chrg irq\n"); | 179 | dev_warn(&pdev->dev, "Failed to request chrg irq\n"); |
184 | } | 180 | } |
185 | 181 | ||
186 | platform_set_drvdata(pdev, ltc3651_charger); | 182 | platform_set_drvdata(pdev, lt3651_charger); |
187 | 183 | ||
188 | return 0; | 184 | return 0; |
189 | } | 185 | } |
190 | 186 | ||
191 | static const struct of_device_id ltc3651_charger_match[] = { | 187 | static const struct of_device_id lt3651_charger_match[] = { |
192 | { .compatible = "lltc,ltc3651-charger" }, | 188 | { .compatible = "lltc,ltc3651-charger" }, /* DEPRECATED */ |
189 | { .compatible = "lltc,lt3651-charger" }, | ||
193 | { } | 190 | { } |
194 | }; | 191 | }; |
195 | MODULE_DEVICE_TABLE(of, ltc3651_charger_match); | 192 | MODULE_DEVICE_TABLE(of, lt3651_charger_match); |
196 | 193 | ||
197 | static struct platform_driver ltc3651_charger_driver = { | 194 | static struct platform_driver lt3651_charger_driver = { |
198 | .probe = ltc3651_charger_probe, | 195 | .probe = lt3651_charger_probe, |
199 | .driver = { | 196 | .driver = { |
200 | .name = "ltc3651-charger", | 197 | .name = "lt3651-charger", |
201 | .of_match_table = ltc3651_charger_match, | 198 | .of_match_table = lt3651_charger_match, |
202 | }, | 199 | }, |
203 | }; | 200 | }; |
204 | 201 | ||
205 | module_platform_driver(ltc3651_charger_driver); | 202 | module_platform_driver(lt3651_charger_driver); |
206 | 203 | ||
207 | MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); | 204 | MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); |
208 | MODULE_DESCRIPTION("Driver for LTC3651 charger"); | 205 | MODULE_DESCRIPTION("Driver for LT3651 charger"); |
209 | MODULE_LICENSE("GPL"); | 206 | MODULE_LICENSE("GPL"); |
210 | MODULE_ALIAS("platform:ltc3651-charger"); | 207 | MODULE_ALIAS("platform:lt3651-charger"); |
diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c index b91b1d2999dc..9e6472834e37 100644 --- a/drivers/power/supply/max14656_charger_detector.c +++ b/drivers/power/supply/max14656_charger_detector.c | |||
@@ -240,6 +240,14 @@ static enum power_supply_property max14656_battery_props[] = { | |||
240 | POWER_SUPPLY_PROP_MANUFACTURER, | 240 | POWER_SUPPLY_PROP_MANUFACTURER, |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static void stop_irq_work(void *data) | ||
244 | { | ||
245 | struct max14656_chip *chip = data; | ||
246 | |||
247 | cancel_delayed_work_sync(&chip->irq_work); | ||
248 | } | ||
249 | |||
250 | |||
243 | static int max14656_probe(struct i2c_client *client, | 251 | static int max14656_probe(struct i2c_client *client, |
244 | const struct i2c_device_id *id) | 252 | const struct i2c_device_id *id) |
245 | { | 253 | { |
@@ -278,7 +286,19 @@ static int max14656_probe(struct i2c_client *client, | |||
278 | if (ret) | 286 | if (ret) |
279 | return -ENODEV; | 287 | return -ENODEV; |
280 | 288 | ||
289 | chip->detect_psy = devm_power_supply_register(dev, | ||
290 | &chip->psy_desc, &psy_cfg); | ||
291 | if (IS_ERR(chip->detect_psy)) { | ||
292 | dev_err(dev, "power_supply_register failed\n"); | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | |||
281 | INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker); | 296 | INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker); |
297 | ret = devm_add_action(dev, stop_irq_work, chip); | ||
298 | if (ret) { | ||
299 | dev_err(dev, "devm_add_action %d failed\n", ret); | ||
300 | return ret; | ||
301 | } | ||
282 | 302 | ||
283 | ret = devm_request_irq(dev, chip->irq, max14656_irq, | 303 | ret = devm_request_irq(dev, chip->irq, max14656_irq, |
284 | IRQF_TRIGGER_FALLING, | 304 | IRQF_TRIGGER_FALLING, |
@@ -289,13 +309,6 @@ static int max14656_probe(struct i2c_client *client, | |||
289 | } | 309 | } |
290 | enable_irq_wake(chip->irq); | 310 | enable_irq_wake(chip->irq); |
291 | 311 | ||
292 | chip->detect_psy = devm_power_supply_register(dev, | ||
293 | &chip->psy_desc, &psy_cfg); | ||
294 | if (IS_ERR(chip->detect_psy)) { | ||
295 | dev_err(dev, "power_supply_register failed\n"); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(2000)); | 312 | schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(2000)); |
300 | 313 | ||
301 | return 0; | 314 | return 0; |
diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index 5a97e42a3547..7720e4c2ac0b 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/of.h> | ||
17 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
18 | #include <linux/power_supply.h> | 19 | #include <linux/power_supply.h> |
19 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
@@ -52,6 +53,14 @@ | |||
52 | 53 | ||
53 | #define BAT_ADDR_MFR_TYPE 0x5F | 54 | #define BAT_ADDR_MFR_TYPE 0x5F |
54 | 55 | ||
56 | struct olpc_battery_data { | ||
57 | struct power_supply *olpc_ac; | ||
58 | struct power_supply *olpc_bat; | ||
59 | char bat_serial[17]; | ||
60 | bool new_proto; | ||
61 | bool little_endian; | ||
62 | }; | ||
63 | |||
55 | /********************************************************************* | 64 | /********************************************************************* |
56 | * Power | 65 | * Power |
57 | *********************************************************************/ | 66 | *********************************************************************/ |
@@ -90,13 +99,10 @@ static const struct power_supply_desc olpc_ac_desc = { | |||
90 | .get_property = olpc_ac_get_prop, | 99 | .get_property = olpc_ac_get_prop, |
91 | }; | 100 | }; |
92 | 101 | ||
93 | static struct power_supply *olpc_ac; | 102 | static int olpc_bat_get_status(struct olpc_battery_data *data, |
94 | 103 | union power_supply_propval *val, uint8_t ec_byte) | |
95 | static char bat_serial[17]; /* Ick */ | ||
96 | |||
97 | static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte) | ||
98 | { | 104 | { |
99 | if (olpc_platform_info.ecver > 0x44) { | 105 | if (data->new_proto) { |
100 | if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE)) | 106 | if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE)) |
101 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | 107 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
102 | else if (ec_byte & BAT_STAT_DISCHARGING) | 108 | else if (ec_byte & BAT_STAT_DISCHARGING) |
@@ -318,6 +324,14 @@ static int olpc_bat_get_voltage_max_design(union power_supply_propval *val) | |||
318 | return ret; | 324 | return ret; |
319 | } | 325 | } |
320 | 326 | ||
327 | static u16 ecword_to_cpu(struct olpc_battery_data *data, u16 ec_word) | ||
328 | { | ||
329 | if (data->little_endian) | ||
330 | return le16_to_cpu((__force __le16)ec_word); | ||
331 | else | ||
332 | return be16_to_cpu((__force __be16)ec_word); | ||
333 | } | ||
334 | |||
321 | /********************************************************************* | 335 | /********************************************************************* |
322 | * Battery properties | 336 | * Battery properties |
323 | *********************************************************************/ | 337 | *********************************************************************/ |
@@ -325,8 +339,9 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
325 | enum power_supply_property psp, | 339 | enum power_supply_property psp, |
326 | union power_supply_propval *val) | 340 | union power_supply_propval *val) |
327 | { | 341 | { |
342 | struct olpc_battery_data *data = power_supply_get_drvdata(psy); | ||
328 | int ret = 0; | 343 | int ret = 0; |
329 | __be16 ec_word; | 344 | u16 ec_word; |
330 | uint8_t ec_byte; | 345 | uint8_t ec_byte; |
331 | __be64 ser_buf; | 346 | __be64 ser_buf; |
332 | 347 | ||
@@ -346,7 +361,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
346 | 361 | ||
347 | switch (psp) { | 362 | switch (psp) { |
348 | case POWER_SUPPLY_PROP_STATUS: | 363 | case POWER_SUPPLY_PROP_STATUS: |
349 | ret = olpc_bat_get_status(val, ec_byte); | 364 | ret = olpc_bat_get_status(data, val, ec_byte); |
350 | if (ret) | 365 | if (ret) |
351 | return ret; | 366 | return ret; |
352 | break; | 367 | break; |
@@ -389,7 +404,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
389 | if (ret) | 404 | if (ret) |
390 | return ret; | 405 | return ret; |
391 | 406 | ||
392 | val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; | 407 | val->intval = ecword_to_cpu(data, ec_word) * 9760L / 32; |
393 | break; | 408 | break; |
394 | case POWER_SUPPLY_PROP_CURRENT_AVG: | 409 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
395 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 410 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
@@ -397,7 +412,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
397 | if (ret) | 412 | if (ret) |
398 | return ret; | 413 | return ret; |
399 | 414 | ||
400 | val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120; | 415 | val->intval = ecword_to_cpu(data, ec_word) * 15625L / 120; |
401 | break; | 416 | break; |
402 | case POWER_SUPPLY_PROP_CAPACITY: | 417 | case POWER_SUPPLY_PROP_CAPACITY: |
403 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); | 418 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); |
@@ -428,29 +443,29 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
428 | if (ret) | 443 | if (ret) |
429 | return ret; | 444 | return ret; |
430 | 445 | ||
431 | val->intval = (s16)be16_to_cpu(ec_word) * 10 / 256; | 446 | val->intval = ecword_to_cpu(data, ec_word) * 10 / 256; |
432 | break; | 447 | break; |
433 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | 448 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: |
434 | ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); | 449 | ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); |
435 | if (ret) | 450 | if (ret) |
436 | return ret; | 451 | return ret; |
437 | 452 | ||
438 | val->intval = (int)be16_to_cpu(ec_word) * 10 / 256; | 453 | val->intval = (int)ecword_to_cpu(data, ec_word) * 10 / 256; |
439 | break; | 454 | break; |
440 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | 455 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: |
441 | ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2); | 456 | ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2); |
442 | if (ret) | 457 | if (ret) |
443 | return ret; | 458 | return ret; |
444 | 459 | ||
445 | val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15; | 460 | val->intval = ecword_to_cpu(data, ec_word) * 6250 / 15; |
446 | break; | 461 | break; |
447 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: | 462 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
448 | ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); | 463 | ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); |
449 | if (ret) | 464 | if (ret) |
450 | return ret; | 465 | return ret; |
451 | 466 | ||
452 | sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf)); | 467 | sprintf(data->bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf)); |
453 | val->strval = bat_serial; | 468 | val->strval = data->bat_serial; |
454 | break; | 469 | break; |
455 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 470 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
456 | ret = olpc_bat_get_voltage_max_design(val); | 471 | ret = olpc_bat_get_voltage_max_design(val); |
@@ -536,7 +551,7 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj, | |||
536 | return count; | 551 | return count; |
537 | } | 552 | } |
538 | 553 | ||
539 | static const struct bin_attribute olpc_bat_eeprom = { | 554 | static struct bin_attribute olpc_bat_eeprom = { |
540 | .attr = { | 555 | .attr = { |
541 | .name = "eeprom", | 556 | .name = "eeprom", |
542 | .mode = S_IRUGO, | 557 | .mode = S_IRUGO, |
@@ -560,7 +575,7 @@ static ssize_t olpc_bat_error_read(struct device *dev, | |||
560 | return sprintf(buf, "%d\n", ec_byte); | 575 | return sprintf(buf, "%d\n", ec_byte); |
561 | } | 576 | } |
562 | 577 | ||
563 | static const struct device_attribute olpc_bat_error = { | 578 | static struct device_attribute olpc_bat_error = { |
564 | .attr = { | 579 | .attr = { |
565 | .name = "error", | 580 | .name = "error", |
566 | .mode = S_IRUGO, | 581 | .mode = S_IRUGO, |
@@ -568,6 +583,27 @@ static const struct device_attribute olpc_bat_error = { | |||
568 | .show = olpc_bat_error_read, | 583 | .show = olpc_bat_error_read, |
569 | }; | 584 | }; |
570 | 585 | ||
586 | static struct attribute *olpc_bat_sysfs_attrs[] = { | ||
587 | &olpc_bat_error.attr, | ||
588 | NULL | ||
589 | }; | ||
590 | |||
591 | static struct bin_attribute *olpc_bat_sysfs_bin_attrs[] = { | ||
592 | &olpc_bat_eeprom, | ||
593 | NULL | ||
594 | }; | ||
595 | |||
596 | static const struct attribute_group olpc_bat_sysfs_group = { | ||
597 | .attrs = olpc_bat_sysfs_attrs, | ||
598 | .bin_attrs = olpc_bat_sysfs_bin_attrs, | ||
599 | |||
600 | }; | ||
601 | |||
602 | static const struct attribute_group *olpc_bat_sysfs_groups[] = { | ||
603 | &olpc_bat_sysfs_group, | ||
604 | NULL | ||
605 | }; | ||
606 | |||
571 | /********************************************************************* | 607 | /********************************************************************* |
572 | * Initialisation | 608 | * Initialisation |
573 | *********************************************************************/ | 609 | *********************************************************************/ |
@@ -578,17 +614,17 @@ static struct power_supply_desc olpc_bat_desc = { | |||
578 | .use_for_apm = 1, | 614 | .use_for_apm = 1, |
579 | }; | 615 | }; |
580 | 616 | ||
581 | static struct power_supply *olpc_bat; | ||
582 | |||
583 | static int olpc_battery_suspend(struct platform_device *pdev, | 617 | static int olpc_battery_suspend(struct platform_device *pdev, |
584 | pm_message_t state) | 618 | pm_message_t state) |
585 | { | 619 | { |
586 | if (device_may_wakeup(&olpc_ac->dev)) | 620 | struct olpc_battery_data *data = platform_get_drvdata(pdev); |
621 | |||
622 | if (device_may_wakeup(&data->olpc_ac->dev)) | ||
587 | olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR); | 623 | olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR); |
588 | else | 624 | else |
589 | olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR); | 625 | olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR); |
590 | 626 | ||
591 | if (device_may_wakeup(&olpc_bat->dev)) | 627 | if (device_may_wakeup(&data->olpc_bat->dev)) |
592 | olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC | 628 | olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC |
593 | | EC_SCI_SRC_BATERR); | 629 | | EC_SCI_SRC_BATERR); |
594 | else | 630 | else |
@@ -600,16 +636,37 @@ static int olpc_battery_suspend(struct platform_device *pdev, | |||
600 | 636 | ||
601 | static int olpc_battery_probe(struct platform_device *pdev) | 637 | static int olpc_battery_probe(struct platform_device *pdev) |
602 | { | 638 | { |
603 | int ret; | 639 | struct power_supply_config bat_psy_cfg = {}; |
640 | struct power_supply_config ac_psy_cfg = {}; | ||
641 | struct olpc_battery_data *data; | ||
604 | uint8_t status; | 642 | uint8_t status; |
643 | uint8_t ecver; | ||
644 | int ret; | ||
645 | |||
646 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
647 | if (!data) | ||
648 | return -ENOMEM; | ||
649 | platform_set_drvdata(pdev, data); | ||
605 | 650 | ||
606 | /* | 651 | /* See if the EC is already there and get the EC revision */ |
607 | * We've seen a number of EC protocol changes; this driver requires | 652 | ret = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ecver, 1); |
608 | * the latest EC protocol, supported by 0x44 and above. | 653 | if (ret) |
609 | */ | 654 | return ret; |
610 | if (olpc_platform_info.ecver < 0x44) { | 655 | |
656 | if (of_find_compatible_node(NULL, NULL, "olpc,xo1.75-ec")) { | ||
657 | /* XO 1.75 */ | ||
658 | data->new_proto = true; | ||
659 | data->little_endian = true; | ||
660 | } else if (ecver > 0x44) { | ||
661 | /* XO 1 or 1.5 with a new EC firmware. */ | ||
662 | data->new_proto = true; | ||
663 | } else if (ecver < 0x44) { | ||
664 | /* | ||
665 | * We've seen a number of EC protocol changes; this driver | ||
666 | * requires the latest EC protocol, supported by 0x44 and above. | ||
667 | */ | ||
611 | printk(KERN_NOTICE "OLPC EC version 0x%02x too old for " | 668 | printk(KERN_NOTICE "OLPC EC version 0x%02x too old for " |
612 | "battery driver.\n", olpc_platform_info.ecver); | 669 | "battery driver.\n", ecver); |
613 | return -ENXIO; | 670 | return -ENXIO; |
614 | } | 671 | } |
615 | 672 | ||
@@ -619,59 +676,44 @@ static int olpc_battery_probe(struct platform_device *pdev) | |||
619 | 676 | ||
620 | /* Ignore the status. It doesn't actually matter */ | 677 | /* Ignore the status. It doesn't actually matter */ |
621 | 678 | ||
622 | olpc_ac = power_supply_register(&pdev->dev, &olpc_ac_desc, NULL); | 679 | ac_psy_cfg.of_node = pdev->dev.of_node; |
623 | if (IS_ERR(olpc_ac)) | 680 | ac_psy_cfg.drv_data = data; |
624 | return PTR_ERR(olpc_ac); | 681 | |
682 | data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc, | ||
683 | &ac_psy_cfg); | ||
684 | if (IS_ERR(data->olpc_ac)) | ||
685 | return PTR_ERR(data->olpc_ac); | ||
625 | 686 | ||
626 | if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ | 687 | if (of_device_is_compatible(pdev->dev.of_node, "olpc,xo1.5-battery")) { |
688 | /* XO-1.5 */ | ||
627 | olpc_bat_desc.properties = olpc_xo15_bat_props; | 689 | olpc_bat_desc.properties = olpc_xo15_bat_props; |
628 | olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); | 690 | olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); |
629 | } else { /* XO-1 */ | 691 | } else { |
692 | /* XO-1 */ | ||
630 | olpc_bat_desc.properties = olpc_xo1_bat_props; | 693 | olpc_bat_desc.properties = olpc_xo1_bat_props; |
631 | olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); | 694 | olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); |
632 | } | 695 | } |
633 | 696 | ||
634 | olpc_bat = power_supply_register(&pdev->dev, &olpc_bat_desc, NULL); | 697 | bat_psy_cfg.of_node = pdev->dev.of_node; |
635 | if (IS_ERR(olpc_bat)) { | 698 | bat_psy_cfg.drv_data = data; |
636 | ret = PTR_ERR(olpc_bat); | 699 | bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups; |
637 | goto battery_failed; | ||
638 | } | ||
639 | |||
640 | ret = device_create_bin_file(&olpc_bat->dev, &olpc_bat_eeprom); | ||
641 | if (ret) | ||
642 | goto eeprom_failed; | ||
643 | 700 | ||
644 | ret = device_create_file(&olpc_bat->dev, &olpc_bat_error); | 701 | data->olpc_bat = devm_power_supply_register(&pdev->dev, &olpc_bat_desc, |
645 | if (ret) | 702 | &bat_psy_cfg); |
646 | goto error_failed; | 703 | if (IS_ERR(data->olpc_bat)) |
704 | return PTR_ERR(data->olpc_bat); | ||
647 | 705 | ||
648 | if (olpc_ec_wakeup_available()) { | 706 | if (olpc_ec_wakeup_available()) { |
649 | device_set_wakeup_capable(&olpc_ac->dev, true); | 707 | device_set_wakeup_capable(&data->olpc_ac->dev, true); |
650 | device_set_wakeup_capable(&olpc_bat->dev, true); | 708 | device_set_wakeup_capable(&data->olpc_bat->dev, true); |
651 | } | 709 | } |
652 | 710 | ||
653 | return 0; | 711 | return 0; |
654 | |||
655 | error_failed: | ||
656 | device_remove_bin_file(&olpc_bat->dev, &olpc_bat_eeprom); | ||
657 | eeprom_failed: | ||
658 | power_supply_unregister(olpc_bat); | ||
659 | battery_failed: | ||
660 | power_supply_unregister(olpc_ac); | ||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | static int olpc_battery_remove(struct platform_device *pdev) | ||
665 | { | ||
666 | device_remove_file(&olpc_bat->dev, &olpc_bat_error); | ||
667 | device_remove_bin_file(&olpc_bat->dev, &olpc_bat_eeprom); | ||
668 | power_supply_unregister(olpc_bat); | ||
669 | power_supply_unregister(olpc_ac); | ||
670 | return 0; | ||
671 | } | 712 | } |
672 | 713 | ||
673 | static const struct of_device_id olpc_battery_ids[] = { | 714 | static const struct of_device_id olpc_battery_ids[] = { |
674 | { .compatible = "olpc,xo1-battery" }, | 715 | { .compatible = "olpc,xo1-battery" }, |
716 | { .compatible = "olpc,xo1.5-battery" }, | ||
675 | {} | 717 | {} |
676 | }; | 718 | }; |
677 | MODULE_DEVICE_TABLE(of, olpc_battery_ids); | 719 | MODULE_DEVICE_TABLE(of, olpc_battery_ids); |
@@ -682,7 +724,6 @@ static struct platform_driver olpc_battery_driver = { | |||
682 | .of_match_table = olpc_battery_ids, | 724 | .of_match_table = olpc_battery_ids, |
683 | }, | 725 | }, |
684 | .probe = olpc_battery_probe, | 726 | .probe = olpc_battery_probe, |
685 | .remove = olpc_battery_remove, | ||
686 | .suspend = olpc_battery_suspend, | 727 | .suspend = olpc_battery_suspend, |
687 | }; | 728 | }; |
688 | 729 | ||
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index c917a8b43b2b..f7033ecf6d0b 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c | |||
@@ -598,10 +598,12 @@ int power_supply_get_battery_info(struct power_supply *psy, | |||
598 | 598 | ||
599 | err = of_property_read_string(battery_np, "compatible", &value); | 599 | err = of_property_read_string(battery_np, "compatible", &value); |
600 | if (err) | 600 | if (err) |
601 | return err; | 601 | goto out_put_node; |
602 | 602 | ||
603 | if (strcmp("simple-battery", value)) | 603 | if (strcmp("simple-battery", value)) { |
604 | return -ENODEV; | 604 | err = -ENODEV; |
605 | goto out_put_node; | ||
606 | } | ||
605 | 607 | ||
606 | /* The property and field names below must correspond to elements | 608 | /* The property and field names below must correspond to elements |
607 | * in enum power_supply_property. For reasoning, see | 609 | * in enum power_supply_property. For reasoning, see |
@@ -620,19 +622,21 @@ int power_supply_get_battery_info(struct power_supply *psy, | |||
620 | &info->precharge_current_ua); | 622 | &info->precharge_current_ua); |
621 | of_property_read_u32(battery_np, "charge-term-current-microamp", | 623 | of_property_read_u32(battery_np, "charge-term-current-microamp", |
622 | &info->charge_term_current_ua); | 624 | &info->charge_term_current_ua); |
623 | of_property_read_u32(battery_np, "constant_charge_current_max_microamp", | 625 | of_property_read_u32(battery_np, "constant-charge-current-max-microamp", |
624 | &info->constant_charge_current_max_ua); | 626 | &info->constant_charge_current_max_ua); |
625 | of_property_read_u32(battery_np, "constant_charge_voltage_max_microvolt", | 627 | of_property_read_u32(battery_np, "constant-charge-voltage-max-microvolt", |
626 | &info->constant_charge_voltage_max_uv); | 628 | &info->constant_charge_voltage_max_uv); |
627 | of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms", | 629 | of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms", |
628 | &info->factory_internal_resistance_uohm); | 630 | &info->factory_internal_resistance_uohm); |
629 | 631 | ||
630 | len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius"); | 632 | len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius"); |
631 | if (len < 0 && len != -EINVAL) { | 633 | if (len < 0 && len != -EINVAL) { |
632 | return len; | 634 | err = len; |
635 | goto out_put_node; | ||
633 | } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) { | 636 | } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) { |
634 | dev_err(&psy->dev, "Too many temperature values\n"); | 637 | dev_err(&psy->dev, "Too many temperature values\n"); |
635 | return -EINVAL; | 638 | err = -EINVAL; |
639 | goto out_put_node; | ||
636 | } else if (len > 0) { | 640 | } else if (len > 0) { |
637 | of_property_read_u32_array(battery_np, "ocv-capacity-celsius", | 641 | of_property_read_u32_array(battery_np, "ocv-capacity-celsius", |
638 | info->ocv_temp, len); | 642 | info->ocv_temp, len); |
@@ -650,7 +654,8 @@ int power_supply_get_battery_info(struct power_supply *psy, | |||
650 | dev_err(&psy->dev, "failed to get %s\n", propname); | 654 | dev_err(&psy->dev, "failed to get %s\n", propname); |
651 | kfree(propname); | 655 | kfree(propname); |
652 | power_supply_put_battery_info(psy, info); | 656 | power_supply_put_battery_info(psy, info); |
653 | return -EINVAL; | 657 | err = -EINVAL; |
658 | goto out_put_node; | ||
654 | } | 659 | } |
655 | 660 | ||
656 | kfree(propname); | 661 | kfree(propname); |
@@ -661,16 +666,21 @@ int power_supply_get_battery_info(struct power_supply *psy, | |||
661 | devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL); | 666 | devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL); |
662 | if (!info->ocv_table[index]) { | 667 | if (!info->ocv_table[index]) { |
663 | power_supply_put_battery_info(psy, info); | 668 | power_supply_put_battery_info(psy, info); |
664 | return -ENOMEM; | 669 | err = -ENOMEM; |
670 | goto out_put_node; | ||
665 | } | 671 | } |
666 | 672 | ||
667 | for (i = 0; i < tab_len; i++) { | 673 | for (i = 0; i < tab_len; i++) { |
668 | table[i].ocv = be32_to_cpu(*list++); | 674 | table[i].ocv = be32_to_cpu(*list); |
669 | table[i].capacity = be32_to_cpu(*list++); | 675 | list++; |
676 | table[i].capacity = be32_to_cpu(*list); | ||
677 | list++; | ||
670 | } | 678 | } |
671 | } | 679 | } |
672 | 680 | ||
673 | return 0; | 681 | out_put_node: |
682 | of_node_put(battery_np); | ||
683 | return err; | ||
674 | } | 684 | } |
675 | EXPORT_SYMBOL_GPL(power_supply_get_battery_info); | 685 | EXPORT_SYMBOL_GPL(power_supply_get_battery_info); |
676 | 686 | ||
@@ -899,7 +909,7 @@ static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd, | |||
899 | return ret; | 909 | return ret; |
900 | } | 910 | } |
901 | 911 | ||
902 | static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd, | 912 | static int ps_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd, |
903 | unsigned long *state) | 913 | unsigned long *state) |
904 | { | 914 | { |
905 | struct power_supply *psy; | 915 | struct power_supply *psy; |
@@ -934,7 +944,7 @@ static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd, | |||
934 | 944 | ||
935 | static const struct thermal_cooling_device_ops psy_tcd_ops = { | 945 | static const struct thermal_cooling_device_ops psy_tcd_ops = { |
936 | .get_max_state = ps_get_max_charge_cntl_limit, | 946 | .get_max_state = ps_get_max_charge_cntl_limit, |
937 | .get_cur_state = ps_get_cur_chrage_cntl_limit, | 947 | .get_cur_state = ps_get_cur_charge_cntl_limit, |
938 | .set_cur_state = ps_set_cur_charge_cntl_limit, | 948 | .set_cur_state = ps_set_cur_charge_cntl_limit, |
939 | }; | 949 | }; |
940 | 950 | ||
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 5358a80d854f..a704a76d7529 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c | |||
@@ -56,13 +56,13 @@ static const char * const power_supply_status_text[] = { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | static const char * const power_supply_charge_type_text[] = { | 58 | static const char * const power_supply_charge_type_text[] = { |
59 | "Unknown", "N/A", "Trickle", "Fast" | 59 | "Unknown", "N/A", "Trickle", "Fast", "Standard", "Adaptive", "Custom" |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static const char * const power_supply_health_text[] = { | 62 | static const char * const power_supply_health_text[] = { |
63 | "Unknown", "Good", "Overheat", "Dead", "Over voltage", | 63 | "Unknown", "Good", "Overheat", "Dead", "Over voltage", |
64 | "Unspecified failure", "Cold", "Watchdog timer expire", | 64 | "Unspecified failure", "Cold", "Watchdog timer expire", |
65 | "Safety timer expire" | 65 | "Safety timer expire", "Over current" |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static const char * const power_supply_technology_text[] = { | 68 | static const char * const power_supply_technology_text[] = { |
@@ -274,6 +274,8 @@ static struct device_attribute power_supply_attrs[] = { | |||
274 | POWER_SUPPLY_ATTR(constant_charge_voltage_max), | 274 | POWER_SUPPLY_ATTR(constant_charge_voltage_max), |
275 | POWER_SUPPLY_ATTR(charge_control_limit), | 275 | POWER_SUPPLY_ATTR(charge_control_limit), |
276 | POWER_SUPPLY_ATTR(charge_control_limit_max), | 276 | POWER_SUPPLY_ATTR(charge_control_limit_max), |
277 | POWER_SUPPLY_ATTR(charge_control_start_threshold), | ||
278 | POWER_SUPPLY_ATTR(charge_control_end_threshold), | ||
277 | POWER_SUPPLY_ATTR(input_current_limit), | 279 | POWER_SUPPLY_ATTR(input_current_limit), |
278 | POWER_SUPPLY_ATTR(energy_full_design), | 280 | POWER_SUPPLY_ATTR(energy_full_design), |
279 | POWER_SUPPLY_ATTR(energy_empty_design), | 281 | POWER_SUPPLY_ATTR(energy_empty_design), |
diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c new file mode 100644 index 000000000000..1c89d030c045 --- /dev/null +++ b/drivers/power/supply/ucs1002_power.c | |||
@@ -0,0 +1,646 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Driver for UCS1002 Programmable USB Port Power Controller | ||
4 | * | ||
5 | * Copyright (C) 2019 Zodiac Inflight Innovations | ||
6 | */ | ||
7 | #include <linux/bits.h> | ||
8 | #include <linux/freezer.h> | ||
9 | #include <linux/gpio/consumer.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/kthread.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_irq.h> | ||
18 | #include <linux/power_supply.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/regulator/driver.h> | ||
21 | #include <linux/regulator/of_regulator.h> | ||
22 | |||
23 | /* UCS1002 Registers */ | ||
24 | #define UCS1002_REG_CURRENT_MEASUREMENT 0x00 | ||
25 | |||
26 | /* | ||
27 | * The Total Accumulated Charge registers store the total accumulated | ||
28 | * charge delivered from the VS source to a portable device. The total | ||
29 | * value is calculated using four registers, from 01h to 04h. The bit | ||
30 | * weighting of the registers is given in mA/hrs. | ||
31 | */ | ||
32 | #define UCS1002_REG_TOTAL_ACC_CHARGE 0x01 | ||
33 | |||
34 | /* Other Status Register */ | ||
35 | #define UCS1002_REG_OTHER_STATUS 0x0f | ||
36 | # define F_ADET_PIN BIT(4) | ||
37 | # define F_CHG_ACT BIT(3) | ||
38 | |||
39 | /* Interrupt Status */ | ||
40 | #define UCS1002_REG_INTERRUPT_STATUS 0x10 | ||
41 | # define F_DISCHARGE_ERR BIT(6) | ||
42 | # define F_RESET BIT(5) | ||
43 | # define F_MIN_KEEP_OUT BIT(4) | ||
44 | # define F_TSD BIT(3) | ||
45 | # define F_OVER_VOLT BIT(2) | ||
46 | # define F_BACK_VOLT BIT(1) | ||
47 | # define F_OVER_ILIM BIT(0) | ||
48 | |||
49 | /* Pin Status Register */ | ||
50 | #define UCS1002_REG_PIN_STATUS 0x14 | ||
51 | # define UCS1002_PWR_STATE_MASK 0x03 | ||
52 | # define F_PWR_EN_PIN BIT(6) | ||
53 | # define F_M2_PIN BIT(5) | ||
54 | # define F_M1_PIN BIT(4) | ||
55 | # define F_EM_EN_PIN BIT(3) | ||
56 | # define F_SEL_PIN BIT(2) | ||
57 | # define F_ACTIVE_MODE_MASK GENMASK(5, 3) | ||
58 | # define F_ACTIVE_MODE_PASSTHROUGH F_M2_PIN | ||
59 | # define F_ACTIVE_MODE_DEDICATED F_EM_EN_PIN | ||
60 | # define F_ACTIVE_MODE_BC12_DCP (F_M2_PIN | F_EM_EN_PIN) | ||
61 | # define F_ACTIVE_MODE_BC12_SDP F_M1_PIN | ||
62 | # define F_ACTIVE_MODE_BC12_CDP (F_M1_PIN | F_M2_PIN | F_EM_EN_PIN) | ||
63 | |||
64 | /* General Configuration Register */ | ||
65 | #define UCS1002_REG_GENERAL_CFG 0x15 | ||
66 | # define F_RATION_EN BIT(3) | ||
67 | |||
68 | /* Emulation Configuration Register */ | ||
69 | #define UCS1002_REG_EMU_CFG 0x16 | ||
70 | |||
71 | /* Switch Configuration Register */ | ||
72 | #define UCS1002_REG_SWITCH_CFG 0x17 | ||
73 | # define F_PIN_IGNORE BIT(7) | ||
74 | # define F_EM_EN_SET BIT(5) | ||
75 | # define F_M2_SET BIT(4) | ||
76 | # define F_M1_SET BIT(3) | ||
77 | # define F_S0_SET BIT(2) | ||
78 | # define F_PWR_EN_SET BIT(1) | ||
79 | # define F_LATCH_SET BIT(0) | ||
80 | # define V_SET_ACTIVE_MODE_MASK GENMASK(5, 3) | ||
81 | # define V_SET_ACTIVE_MODE_PASSTHROUGH F_M2_SET | ||
82 | # define V_SET_ACTIVE_MODE_DEDICATED F_EM_EN_SET | ||
83 | # define V_SET_ACTIVE_MODE_BC12_DCP (F_M2_SET | F_EM_EN_SET) | ||
84 | # define V_SET_ACTIVE_MODE_BC12_SDP F_M1_SET | ||
85 | # define V_SET_ACTIVE_MODE_BC12_CDP (F_M1_SET | F_M2_SET | F_EM_EN_SET) | ||
86 | |||
87 | /* Current Limit Register */ | ||
88 | #define UCS1002_REG_ILIMIT 0x19 | ||
89 | # define UCS1002_ILIM_SW_MASK GENMASK(3, 0) | ||
90 | |||
91 | /* Product ID */ | ||
92 | #define UCS1002_REG_PRODUCT_ID 0xfd | ||
93 | # define UCS1002_PRODUCT_ID 0x4e | ||
94 | |||
95 | /* Manufacture name */ | ||
96 | #define UCS1002_MANUFACTURER "SMSC" | ||
97 | |||
98 | struct ucs1002_info { | ||
99 | struct power_supply *charger; | ||
100 | struct i2c_client *client; | ||
101 | struct regmap *regmap; | ||
102 | struct regulator_desc *regulator_descriptor; | ||
103 | bool present; | ||
104 | }; | ||
105 | |||
106 | static enum power_supply_property ucs1002_props[] = { | ||
107 | POWER_SUPPLY_PROP_ONLINE, | ||
108 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
109 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
110 | POWER_SUPPLY_PROP_CURRENT_MAX, | ||
111 | POWER_SUPPLY_PROP_PRESENT, /* the presence of PED */ | ||
112 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
113 | POWER_SUPPLY_PROP_USB_TYPE, | ||
114 | POWER_SUPPLY_PROP_HEALTH, | ||
115 | }; | ||
116 | |||
117 | static int ucs1002_get_online(struct ucs1002_info *info, | ||
118 | union power_supply_propval *val) | ||
119 | { | ||
120 | unsigned int reg; | ||
121 | int ret; | ||
122 | |||
123 | ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, ®); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | |||
127 | val->intval = !!(reg & F_CHG_ACT); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int ucs1002_get_charge(struct ucs1002_info *info, | ||
133 | union power_supply_propval *val) | ||
134 | { | ||
135 | /* | ||
136 | * To fit within 32 bits some values are rounded (uA/h) | ||
137 | * | ||
138 | * For Total Accumulated Charge Middle Low Byte register, addr | ||
139 | * 03h, byte 2 | ||
140 | * | ||
141 | * B0: 0.01084 mA/h rounded to 11 uA/h | ||
142 | * B1: 0.02169 mA/h rounded to 22 uA/h | ||
143 | * B2: 0.04340 mA/h rounded to 43 uA/h | ||
144 | * B3: 0.08676 mA/h rounded to 87 uA/h | ||
145 | * B4: 0.17350 mA/h rounded to 173 uÁ/h | ||
146 | * | ||
147 | * For Total Accumulated Charge Low Byte register, addr 04h, | ||
148 | * byte 3 | ||
149 | * | ||
150 | * B6: 0.00271 mA/h rounded to 3 uA/h | ||
151 | * B7: 0.005422 mA/h rounded to 5 uA/h | ||
152 | */ | ||
153 | static const int bit_weights_uAh[BITS_PER_TYPE(u32)] = { | ||
154 | /* | ||
155 | * Bit corresponding to low byte (offset 0x04) | ||
156 | * B0 B1 B2 B3 B4 B5 B6 B7 | ||
157 | */ | ||
158 | 0, 0, 0, 0, 0, 0, 3, 5, | ||
159 | /* | ||
160 | * Bit corresponding to middle low byte (offset 0x03) | ||
161 | * B0 B1 B2 B3 B4 B5 B6 B7 | ||
162 | */ | ||
163 | 11, 22, 43, 87, 173, 347, 694, 1388, | ||
164 | /* | ||
165 | * Bit corresponding to middle high byte (offset 0x02) | ||
166 | * B0 B1 B2 B3 B4 B5 B6 B7 | ||
167 | */ | ||
168 | 2776, 5552, 11105, 22210, 44420, 88840, 177700, 355400, | ||
169 | /* | ||
170 | * Bit corresponding to high byte (offset 0x01) | ||
171 | * B0 B1 B2 B3 B4 B5 B6 B7 | ||
172 | */ | ||
173 | 710700, 1421000, 2843000, 5685000, 11371000, 22742000, | ||
174 | 45484000, 90968000, | ||
175 | }; | ||
176 | unsigned long total_acc_charger; | ||
177 | unsigned int reg; | ||
178 | int i, ret; | ||
179 | |||
180 | ret = regmap_bulk_read(info->regmap, UCS1002_REG_TOTAL_ACC_CHARGE, | ||
181 | ®, sizeof(u32)); | ||
182 | if (ret) | ||
183 | return ret; | ||
184 | |||
185 | total_acc_charger = be32_to_cpu(reg); /* BE as per offsets above */ | ||
186 | val->intval = 0; | ||
187 | |||
188 | for_each_set_bit(i, &total_acc_charger, ARRAY_SIZE(bit_weights_uAh)) | ||
189 | val->intval += bit_weights_uAh[i]; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int ucs1002_get_current(struct ucs1002_info *info, | ||
195 | union power_supply_propval *val) | ||
196 | { | ||
197 | /* | ||
198 | * The Current Measurement register stores the measured | ||
199 | * current value delivered to the portable device. The range | ||
200 | * is from 9.76 mA to 2.5 A. | ||
201 | */ | ||
202 | static const int bit_weights_uA[BITS_PER_TYPE(u8)] = { | ||
203 | 9760, 19500, 39000, 78100, 156200, 312300, 624600, 1249300, | ||
204 | }; | ||
205 | unsigned long current_measurement; | ||
206 | unsigned int reg; | ||
207 | int i, ret; | ||
208 | |||
209 | ret = regmap_read(info->regmap, UCS1002_REG_CURRENT_MEASUREMENT, ®); | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | current_measurement = reg; | ||
214 | val->intval = 0; | ||
215 | |||
216 | for_each_set_bit(i, ¤t_measurement, ARRAY_SIZE(bit_weights_uA)) | ||
217 | val->intval += bit_weights_uA[i]; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * The Current Limit register stores the maximum current used by the | ||
224 | * port switch. The range is from 500mA to 2.5 A. | ||
225 | */ | ||
226 | static const u32 ucs1002_current_limit_uA[] = { | ||
227 | 500000, 900000, 1000000, 1200000, 1500000, 1800000, 2000000, 2500000, | ||
228 | }; | ||
229 | |||
230 | static int ucs1002_get_max_current(struct ucs1002_info *info, | ||
231 | union power_supply_propval *val) | ||
232 | { | ||
233 | unsigned int reg; | ||
234 | int ret; | ||
235 | |||
236 | ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, ®); | ||
237 | if (ret) | ||
238 | return ret; | ||
239 | |||
240 | val->intval = ucs1002_current_limit_uA[reg & UCS1002_ILIM_SW_MASK]; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int ucs1002_set_max_current(struct ucs1002_info *info, u32 val) | ||
246 | { | ||
247 | unsigned int reg; | ||
248 | int ret, idx; | ||
249 | |||
250 | for (idx = 0; idx < ARRAY_SIZE(ucs1002_current_limit_uA); idx++) { | ||
251 | if (val == ucs1002_current_limit_uA[idx]) | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (idx == ARRAY_SIZE(ucs1002_current_limit_uA)) | ||
256 | return -EINVAL; | ||
257 | |||
258 | ret = regmap_write(info->regmap, UCS1002_REG_ILIMIT, idx); | ||
259 | if (ret) | ||
260 | return ret; | ||
261 | /* | ||
262 | * Any current limit setting exceeding the one set via ILIM | ||
263 | * pin will be rejected, so we read out freshly changed limit | ||
264 | * to make sure that it took effect. | ||
265 | */ | ||
266 | ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, ®); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | if (reg != idx) | ||
271 | return -EINVAL; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static enum power_supply_usb_type ucs1002_usb_types[] = { | ||
277 | POWER_SUPPLY_USB_TYPE_PD, | ||
278 | POWER_SUPPLY_USB_TYPE_SDP, | ||
279 | POWER_SUPPLY_USB_TYPE_DCP, | ||
280 | POWER_SUPPLY_USB_TYPE_CDP, | ||
281 | POWER_SUPPLY_USB_TYPE_UNKNOWN, | ||
282 | }; | ||
283 | |||
284 | static int ucs1002_set_usb_type(struct ucs1002_info *info, int val) | ||
285 | { | ||
286 | unsigned int mode; | ||
287 | |||
288 | if (val < 0 || val >= ARRAY_SIZE(ucs1002_usb_types)) | ||
289 | return -EINVAL; | ||
290 | |||
291 | switch (ucs1002_usb_types[val]) { | ||
292 | case POWER_SUPPLY_USB_TYPE_PD: | ||
293 | mode = V_SET_ACTIVE_MODE_DEDICATED; | ||
294 | break; | ||
295 | case POWER_SUPPLY_USB_TYPE_SDP: | ||
296 | mode = V_SET_ACTIVE_MODE_BC12_SDP; | ||
297 | break; | ||
298 | case POWER_SUPPLY_USB_TYPE_DCP: | ||
299 | mode = V_SET_ACTIVE_MODE_BC12_DCP; | ||
300 | break; | ||
301 | case POWER_SUPPLY_USB_TYPE_CDP: | ||
302 | mode = V_SET_ACTIVE_MODE_BC12_CDP; | ||
303 | break; | ||
304 | default: | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | return regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG, | ||
309 | V_SET_ACTIVE_MODE_MASK, mode); | ||
310 | } | ||
311 | |||
312 | static int ucs1002_get_usb_type(struct ucs1002_info *info, | ||
313 | union power_supply_propval *val) | ||
314 | { | ||
315 | enum power_supply_usb_type type; | ||
316 | unsigned int reg; | ||
317 | int ret; | ||
318 | |||
319 | ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, ®); | ||
320 | if (ret) | ||
321 | return ret; | ||
322 | |||
323 | switch (reg & F_ACTIVE_MODE_MASK) { | ||
324 | default: | ||
325 | type = POWER_SUPPLY_USB_TYPE_UNKNOWN; | ||
326 | break; | ||
327 | case F_ACTIVE_MODE_DEDICATED: | ||
328 | type = POWER_SUPPLY_USB_TYPE_PD; | ||
329 | break; | ||
330 | case F_ACTIVE_MODE_BC12_SDP: | ||
331 | type = POWER_SUPPLY_USB_TYPE_SDP; | ||
332 | break; | ||
333 | case F_ACTIVE_MODE_BC12_DCP: | ||
334 | type = POWER_SUPPLY_USB_TYPE_DCP; | ||
335 | break; | ||
336 | case F_ACTIVE_MODE_BC12_CDP: | ||
337 | type = POWER_SUPPLY_USB_TYPE_CDP; | ||
338 | break; | ||
339 | }; | ||
340 | |||
341 | val->intval = type; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int ucs1002_get_health(struct ucs1002_info *info, | ||
347 | union power_supply_propval *val) | ||
348 | { | ||
349 | unsigned int reg; | ||
350 | int ret, health; | ||
351 | |||
352 | ret = regmap_read(info->regmap, UCS1002_REG_INTERRUPT_STATUS, ®); | ||
353 | if (ret) | ||
354 | return ret; | ||
355 | |||
356 | if (reg & F_TSD) | ||
357 | health = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
358 | else if (reg & (F_OVER_VOLT | F_BACK_VOLT)) | ||
359 | health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | ||
360 | else if (reg & F_OVER_ILIM) | ||
361 | health = POWER_SUPPLY_HEALTH_OVERCURRENT; | ||
362 | else if (reg & (F_DISCHARGE_ERR | F_MIN_KEEP_OUT)) | ||
363 | health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
364 | else | ||
365 | health = POWER_SUPPLY_HEALTH_GOOD; | ||
366 | |||
367 | val->intval = health; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int ucs1002_get_property(struct power_supply *psy, | ||
373 | enum power_supply_property psp, | ||
374 | union power_supply_propval *val) | ||
375 | { | ||
376 | struct ucs1002_info *info = power_supply_get_drvdata(psy); | ||
377 | |||
378 | switch (psp) { | ||
379 | case POWER_SUPPLY_PROP_ONLINE: | ||
380 | return ucs1002_get_online(info, val); | ||
381 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
382 | return ucs1002_get_charge(info, val); | ||
383 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
384 | return ucs1002_get_current(info, val); | ||
385 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
386 | return ucs1002_get_max_current(info, val); | ||
387 | case POWER_SUPPLY_PROP_USB_TYPE: | ||
388 | return ucs1002_get_usb_type(info, val); | ||
389 | case POWER_SUPPLY_PROP_HEALTH: | ||
390 | return ucs1002_get_health(info, val); | ||
391 | case POWER_SUPPLY_PROP_PRESENT: | ||
392 | val->intval = info->present; | ||
393 | return 0; | ||
394 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
395 | val->strval = UCS1002_MANUFACTURER; | ||
396 | return 0; | ||
397 | default: | ||
398 | return -EINVAL; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | static int ucs1002_set_property(struct power_supply *psy, | ||
403 | enum power_supply_property psp, | ||
404 | const union power_supply_propval *val) | ||
405 | { | ||
406 | struct ucs1002_info *info = power_supply_get_drvdata(psy); | ||
407 | |||
408 | switch (psp) { | ||
409 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
410 | return ucs1002_set_max_current(info, val->intval); | ||
411 | case POWER_SUPPLY_PROP_USB_TYPE: | ||
412 | return ucs1002_set_usb_type(info, val->intval); | ||
413 | default: | ||
414 | return -EINVAL; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | static int ucs1002_property_is_writeable(struct power_supply *psy, | ||
419 | enum power_supply_property psp) | ||
420 | { | ||
421 | switch (psp) { | ||
422 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
423 | case POWER_SUPPLY_PROP_USB_TYPE: | ||
424 | return true; | ||
425 | default: | ||
426 | return false; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static const struct power_supply_desc ucs1002_charger_desc = { | ||
431 | .name = "ucs1002", | ||
432 | .type = POWER_SUPPLY_TYPE_USB, | ||
433 | .usb_types = ucs1002_usb_types, | ||
434 | .num_usb_types = ARRAY_SIZE(ucs1002_usb_types), | ||
435 | .get_property = ucs1002_get_property, | ||
436 | .set_property = ucs1002_set_property, | ||
437 | .property_is_writeable = ucs1002_property_is_writeable, | ||
438 | .properties = ucs1002_props, | ||
439 | .num_properties = ARRAY_SIZE(ucs1002_props), | ||
440 | }; | ||
441 | |||
442 | static irqreturn_t ucs1002_charger_irq(int irq, void *data) | ||
443 | { | ||
444 | int ret, regval; | ||
445 | bool present; | ||
446 | struct ucs1002_info *info = data; | ||
447 | |||
448 | present = info->present; | ||
449 | |||
450 | ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, ®val); | ||
451 | if (ret) | ||
452 | return IRQ_HANDLED; | ||
453 | |||
454 | /* update attached status */ | ||
455 | info->present = regval & F_ADET_PIN; | ||
456 | |||
457 | /* notify the change */ | ||
458 | if (present != info->present) | ||
459 | power_supply_changed(info->charger); | ||
460 | |||
461 | return IRQ_HANDLED; | ||
462 | } | ||
463 | |||
464 | static irqreturn_t ucs1002_alert_irq(int irq, void *data) | ||
465 | { | ||
466 | struct ucs1002_info *info = data; | ||
467 | |||
468 | power_supply_changed(info->charger); | ||
469 | |||
470 | return IRQ_HANDLED; | ||
471 | } | ||
472 | |||
473 | static const struct regulator_ops ucs1002_regulator_ops = { | ||
474 | .is_enabled = regulator_is_enabled_regmap, | ||
475 | .enable = regulator_enable_regmap, | ||
476 | .disable = regulator_disable_regmap, | ||
477 | }; | ||
478 | |||
479 | static const struct regulator_desc ucs1002_regulator_descriptor = { | ||
480 | .name = "ucs1002-vbus", | ||
481 | .ops = &ucs1002_regulator_ops, | ||
482 | .type = REGULATOR_VOLTAGE, | ||
483 | .owner = THIS_MODULE, | ||
484 | .enable_reg = UCS1002_REG_SWITCH_CFG, | ||
485 | .enable_mask = F_PWR_EN_SET, | ||
486 | .enable_val = F_PWR_EN_SET, | ||
487 | .fixed_uV = 5000000, | ||
488 | .n_voltages = 1, | ||
489 | }; | ||
490 | |||
491 | static int ucs1002_probe(struct i2c_client *client, | ||
492 | const struct i2c_device_id *dev_id) | ||
493 | { | ||
494 | struct device *dev = &client->dev; | ||
495 | struct power_supply_config charger_config = {}; | ||
496 | const struct regmap_config regmap_config = { | ||
497 | .reg_bits = 8, | ||
498 | .val_bits = 8, | ||
499 | }; | ||
500 | struct regulator_config regulator_config = {}; | ||
501 | int irq_a_det, irq_alert, ret; | ||
502 | struct regulator_dev *rdev; | ||
503 | struct ucs1002_info *info; | ||
504 | unsigned int regval; | ||
505 | |||
506 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | ||
507 | if (!info) | ||
508 | return -ENOMEM; | ||
509 | |||
510 | info->regmap = devm_regmap_init_i2c(client, ®map_config); | ||
511 | ret = PTR_ERR_OR_ZERO(info->regmap); | ||
512 | if (ret) { | ||
513 | dev_err(dev, "Regmap initialization failed: %d\n", ret); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | info->client = client; | ||
518 | |||
519 | irq_a_det = of_irq_get_byname(dev->of_node, "a_det"); | ||
520 | irq_alert = of_irq_get_byname(dev->of_node, "alert"); | ||
521 | |||
522 | charger_config.of_node = dev->of_node; | ||
523 | charger_config.drv_data = info; | ||
524 | |||
525 | ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, ®val); | ||
526 | if (ret) { | ||
527 | dev_err(dev, "Failed to read product ID: %d\n", ret); | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | if (regval != UCS1002_PRODUCT_ID) { | ||
532 | dev_err(dev, | ||
533 | "Product ID does not match (0x%02x != 0x%02x)\n", | ||
534 | regval, UCS1002_PRODUCT_ID); | ||
535 | return -ENODEV; | ||
536 | } | ||
537 | |||
538 | /* Enable charge rationing by default */ | ||
539 | ret = regmap_update_bits(info->regmap, UCS1002_REG_GENERAL_CFG, | ||
540 | F_RATION_EN, F_RATION_EN); | ||
541 | if (ret) { | ||
542 | dev_err(dev, "Failed to read general config: %d\n", ret); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * Ignore the M1, M2, PWR_EN, and EM_EN pin states. Set active | ||
548 | * mode selection to BC1.2 CDP. | ||
549 | */ | ||
550 | ret = regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG, | ||
551 | V_SET_ACTIVE_MODE_MASK | F_PIN_IGNORE, | ||
552 | V_SET_ACTIVE_MODE_BC12_CDP | F_PIN_IGNORE); | ||
553 | if (ret) { | ||
554 | dev_err(dev, "Failed to configure default mode: %d\n", ret); | ||
555 | return ret; | ||
556 | } | ||
557 | /* | ||
558 | * Be safe and set initial current limit to 500mA | ||
559 | */ | ||
560 | ret = ucs1002_set_max_current(info, 500000); | ||
561 | if (ret) { | ||
562 | dev_err(dev, "Failed to set max current default: %d\n", ret); | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | info->charger = devm_power_supply_register(dev, &ucs1002_charger_desc, | ||
567 | &charger_config); | ||
568 | ret = PTR_ERR_OR_ZERO(info->charger); | ||
569 | if (ret) { | ||
570 | dev_err(dev, "Failed to register power supply: %d\n", ret); | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, ®val); | ||
575 | if (ret) { | ||
576 | dev_err(dev, "Failed to read pin status: %d\n", ret); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | info->regulator_descriptor = | ||
581 | devm_kmemdup(dev, &ucs1002_regulator_descriptor, | ||
582 | sizeof(ucs1002_regulator_descriptor), | ||
583 | GFP_KERNEL); | ||
584 | if (!info->regulator_descriptor) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | info->regulator_descriptor->enable_is_inverted = !(regval & F_SEL_PIN); | ||
588 | |||
589 | regulator_config.dev = dev; | ||
590 | regulator_config.of_node = dev->of_node; | ||
591 | regulator_config.regmap = info->regmap; | ||
592 | |||
593 | rdev = devm_regulator_register(dev, info->regulator_descriptor, | ||
594 | ®ulator_config); | ||
595 | ret = PTR_ERR_OR_ZERO(rdev); | ||
596 | if (ret) { | ||
597 | dev_err(dev, "Failed to register VBUS regulator: %d\n", ret); | ||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | if (irq_a_det > 0) { | ||
602 | ret = devm_request_threaded_irq(dev, irq_a_det, NULL, | ||
603 | ucs1002_charger_irq, | ||
604 | IRQF_ONESHOT, | ||
605 | "ucs1002-a_det", info); | ||
606 | if (ret) { | ||
607 | dev_err(dev, "Failed to request A_DET threaded irq: %d\n", | ||
608 | ret); | ||
609 | return ret; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | if (irq_alert > 0) { | ||
614 | ret = devm_request_threaded_irq(dev, irq_alert, NULL, | ||
615 | ucs1002_alert_irq, | ||
616 | IRQF_ONESHOT, | ||
617 | "ucs1002-alert", info); | ||
618 | if (ret) { | ||
619 | dev_err(dev, "Failed to request ALERT threaded irq: %d\n", | ||
620 | ret); | ||
621 | return ret; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static const struct of_device_id ucs1002_of_match[] = { | ||
629 | { .compatible = "microchip,ucs1002", }, | ||
630 | { /* sentinel */ }, | ||
631 | }; | ||
632 | MODULE_DEVICE_TABLE(of, ucs1002_of_match); | ||
633 | |||
634 | static struct i2c_driver ucs1002_driver = { | ||
635 | .driver = { | ||
636 | .name = "ucs1002", | ||
637 | .of_match_table = ucs1002_of_match, | ||
638 | }, | ||
639 | .probe = ucs1002_probe, | ||
640 | }; | ||
641 | module_i2c_driver(ucs1002_driver); | ||
642 | |||
643 | MODULE_DESCRIPTION("Microchip UCS1002 Programmable USB Port Power Controller"); | ||
644 | MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>"); | ||
645 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
646 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 9887f4f8e2a8..b2d34831ed7c 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h | |||
@@ -291,6 +291,20 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, | |||
291 | const int **vals, int *length); | 291 | const int **vals, int *length); |
292 | 292 | ||
293 | /** | 293 | /** |
294 | * iio_read_avail_channel_attribute() - read available channel attribute values | ||
295 | * @chan: The channel being queried. | ||
296 | * @vals: Available values read back. | ||
297 | * @type: Type of values read back. | ||
298 | * @length: Number of entries in vals. | ||
299 | * @attribute: info attribute to be read back. | ||
300 | * | ||
301 | * Returns an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST. | ||
302 | */ | ||
303 | int iio_read_avail_channel_attribute(struct iio_channel *chan, | ||
304 | const int **vals, int *type, int *length, | ||
305 | enum iio_chan_info_enum attribute); | ||
306 | |||
307 | /** | ||
294 | * iio_get_channel_type() - get the type of a channel | 308 | * iio_get_channel_type() - get the type of a channel |
295 | * @channel: The channel being queried. | 309 | * @channel: The channel being queried. |
296 | * @type: The type of the channel. | 310 | * @type: The type of the channel. |
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 2f9c201a54d1..d9c0c094f8a0 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
@@ -40,11 +40,15 @@ enum { | |||
40 | POWER_SUPPLY_STATUS_FULL, | 40 | POWER_SUPPLY_STATUS_FULL, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* What algorithm is the charger using? */ | ||
43 | enum { | 44 | enum { |
44 | POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0, | 45 | POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0, |
45 | POWER_SUPPLY_CHARGE_TYPE_NONE, | 46 | POWER_SUPPLY_CHARGE_TYPE_NONE, |
46 | POWER_SUPPLY_CHARGE_TYPE_TRICKLE, | 47 | POWER_SUPPLY_CHARGE_TYPE_TRICKLE, /* slow speed */ |
47 | POWER_SUPPLY_CHARGE_TYPE_FAST, | 48 | POWER_SUPPLY_CHARGE_TYPE_FAST, /* fast speed */ |
49 | POWER_SUPPLY_CHARGE_TYPE_STANDARD, /* normal speed */ | ||
50 | POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE, /* dynamically adjusted speed */ | ||
51 | POWER_SUPPLY_CHARGE_TYPE_CUSTOM, /* use CHARGE_CONTROL_* props */ | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | enum { | 54 | enum { |
@@ -57,6 +61,7 @@ enum { | |||
57 | POWER_SUPPLY_HEALTH_COLD, | 61 | POWER_SUPPLY_HEALTH_COLD, |
58 | POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE, | 62 | POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE, |
59 | POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE, | 63 | POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE, |
64 | POWER_SUPPLY_HEALTH_OVERCURRENT, | ||
60 | }; | 65 | }; |
61 | 66 | ||
62 | enum { | 67 | enum { |
@@ -121,6 +126,8 @@ enum power_supply_property { | |||
121 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, | 126 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, |
122 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, | 127 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, |
123 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, | 128 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, |
129 | POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */ | ||
130 | POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */ | ||
124 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, | 131 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, |
125 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | 132 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
126 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, | 133 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, |