diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-21 21:06:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-21 21:06:27 -0400 |
commit | c1fecabecc352e40f99e6c5d7a74b8fcdfb38ae1 (patch) | |
tree | 9ba08f67988d1f45602ea0276555564ebce02b28 /drivers | |
parent | 99cc7ad46b62ef20b0478147677bebd1157bd9cf (diff) | |
parent | 5198a48381455969aa1053a0ca2e4ce409be2fc2 (diff) |
Merge tag 'for-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply and reset updates from Sebastian Reichel:
- Improve support for TI bq20z75 in sbs-battery
- Add Qualcomm PM8xxx reboot driver
- Add cros-ec USBPD charger driver
- Move ds2760 battery driver from w1 to power-supply and add DT support
- Misc fixes
* tag 'for-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (28 commits)
power: supply: bq27xxx: Update comments
power: supply: max77693_charger: fix unintentional fall-through
power: supply: mark expected switch fall-throughs
power: supply: lego_ev3_battery: fix Vce offset
power: supply: lego_ev3_battery: Don't ignore iio_read_channel_processed() return value
power: supply: ds2760_battery: add devicetree probing
power: supply: ds2760_battery: merge ds2760 supply driver with its w1 slave companion
w1: core: match sub-nodes of bus masters in devicetree
dt-bindings: w1: document bindings for ds2760 battery monitor
dt-bindings: w1: document generic onewire bindings
power: supply: adp5061: Fix a couple off by ones
dt-bindings: power: reset: qcom: Add resin binding
adp5061: New driver for ADP5061 I2C battery charger
power: generic-adc-battery: check for duplicate properties copied from iio channels
power: generic-adc-battery: fix out-of-bounds write when copying channel properties
power: supply: axp288_charger: Fix initial constant_charge_current value
power: supply: ab8500: stop using getnstimeofday64()
power: gemini-poweroff: Avoid more spurious poweroffs
power: vexpress: fix corruption in notifier registration
power: remove possible deadlock when unregistering power_supply
...
Diffstat (limited to 'drivers')
28 files changed, 1810 insertions, 402 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index df58fc878b3e..6533aa560aa1 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
@@ -104,6 +104,17 @@ config POWER_RESET_MSM | |||
104 | help | 104 | help |
105 | Power off and restart support for Qualcomm boards. | 105 | Power off and restart support for Qualcomm boards. |
106 | 106 | ||
107 | config POWER_RESET_QCOM_PON | ||
108 | tristate "Qualcomm power-on driver" | ||
109 | depends on ARCH_QCOM | ||
110 | depends on MFD_SPMI_PMIC | ||
111 | select REBOOT_MODE | ||
112 | help | ||
113 | Power On support for Qualcomm boards. | ||
114 | If you have a Qualcomm platform and need support for | ||
115 | power-on and reboot reason, Say Y. | ||
116 | If unsure, Say N. | ||
117 | |||
107 | config POWER_RESET_OCELOT_RESET | 118 | config POWER_RESET_OCELOT_RESET |
108 | bool "Microsemi Ocelot reset driver" | 119 | bool "Microsemi Ocelot reset driver" |
109 | depends on MSCC_OCELOT || COMPILE_TEST | 120 | depends on MSCC_OCELOT || COMPILE_TEST |
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 7778c7485cf1..0aebee954ac1 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o | |||
11 | obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o | 11 | obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o |
12 | obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o | 12 | obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o |
13 | obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o | 13 | obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o |
14 | obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o | ||
14 | obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o | 15 | obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o |
15 | obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o | 16 | obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o |
16 | obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o | 17 | obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o |
diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c index 2ac291af1265..90e35c07240a 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c | |||
@@ -130,7 +130,17 @@ static int gemini_poweroff_probe(struct platform_device *pdev) | |||
130 | val |= GEMINI_CTRL_ENABLE; | 130 | val |= GEMINI_CTRL_ENABLE; |
131 | writel(val, gpw->base + GEMINI_PWC_CTRLREG); | 131 | writel(val, gpw->base + GEMINI_PWC_CTRLREG); |
132 | 132 | ||
133 | /* Now that the state machine is active, clear the IRQ */ | 133 | /* Clear the IRQ */ |
134 | val = readl(gpw->base + GEMINI_PWC_CTRLREG); | ||
135 | val |= GEMINI_CTRL_IRQ_CLR; | ||
136 | writel(val, gpw->base + GEMINI_PWC_CTRLREG); | ||
137 | |||
138 | /* Wait for this to clear */ | ||
139 | val = readl(gpw->base + GEMINI_PWC_STATREG); | ||
140 | while (val & 0x70U) | ||
141 | val = readl(gpw->base + GEMINI_PWC_STATREG); | ||
142 | |||
143 | /* Clear the IRQ again */ | ||
134 | val = readl(gpw->base + GEMINI_PWC_CTRLREG); | 144 | val = readl(gpw->base + GEMINI_PWC_CTRLREG); |
135 | val |= GEMINI_CTRL_IRQ_CLR; | 145 | val |= GEMINI_CTRL_IRQ_CLR; |
136 | writel(val, gpw->base + GEMINI_PWC_CTRLREG); | 146 | writel(val, gpw->base + GEMINI_PWC_CTRLREG); |
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c new file mode 100644 index 000000000000..0c4caaa7e88f --- /dev/null +++ b/drivers/power/reset/qcom-pon.c | |||
@@ -0,0 +1,91 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2017-18 Linaro Limited | ||
3 | |||
4 | #include <linux/delay.h> | ||
5 | #include <linux/errno.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/of.h> | ||
9 | #include <linux/of_platform.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/reboot.h> | ||
12 | #include <linux/reboot-mode.h> | ||
13 | #include <linux/regmap.h> | ||
14 | |||
15 | #define PON_SOFT_RB_SPARE 0x8f | ||
16 | |||
17 | struct pm8916_pon { | ||
18 | struct device *dev; | ||
19 | struct regmap *regmap; | ||
20 | u32 baseaddr; | ||
21 | struct reboot_mode_driver reboot_mode; | ||
22 | }; | ||
23 | |||
24 | static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, | ||
25 | unsigned int magic) | ||
26 | { | ||
27 | struct pm8916_pon *pon = container_of | ||
28 | (reboot, struct pm8916_pon, reboot_mode); | ||
29 | int ret; | ||
30 | |||
31 | ret = regmap_update_bits(pon->regmap, | ||
32 | pon->baseaddr + PON_SOFT_RB_SPARE, | ||
33 | 0xfc, magic << 2); | ||
34 | if (ret < 0) | ||
35 | dev_err(pon->dev, "update reboot mode bits failed\n"); | ||
36 | |||
37 | return ret; | ||
38 | } | ||
39 | |||
40 | static int pm8916_pon_probe(struct platform_device *pdev) | ||
41 | { | ||
42 | struct pm8916_pon *pon; | ||
43 | int error; | ||
44 | |||
45 | pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL); | ||
46 | if (!pon) | ||
47 | return -ENOMEM; | ||
48 | |||
49 | pon->dev = &pdev->dev; | ||
50 | |||
51 | pon->regmap = dev_get_regmap(pdev->dev.parent, NULL); | ||
52 | if (!pon->regmap) { | ||
53 | dev_err(&pdev->dev, "failed to locate regmap\n"); | ||
54 | return -ENODEV; | ||
55 | } | ||
56 | |||
57 | error = of_property_read_u32(pdev->dev.of_node, "reg", | ||
58 | &pon->baseaddr); | ||
59 | if (error) | ||
60 | return error; | ||
61 | |||
62 | pon->reboot_mode.dev = &pdev->dev; | ||
63 | pon->reboot_mode.write = pm8916_reboot_mode_write; | ||
64 | error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode); | ||
65 | if (error) { | ||
66 | dev_err(&pdev->dev, "can't register reboot mode\n"); | ||
67 | return error; | ||
68 | } | ||
69 | |||
70 | platform_set_drvdata(pdev, pon); | ||
71 | |||
72 | return devm_of_platform_populate(&pdev->dev); | ||
73 | } | ||
74 | |||
75 | static const struct of_device_id pm8916_pon_id_table[] = { | ||
76 | { .compatible = "qcom,pm8916-pon" }, | ||
77 | { } | ||
78 | }; | ||
79 | MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); | ||
80 | |||
81 | static struct platform_driver pm8916_pon_driver = { | ||
82 | .probe = pm8916_pon_probe, | ||
83 | .driver = { | ||
84 | .name = "pm8916-pon", | ||
85 | .of_match_table = of_match_ptr(pm8916_pon_id_table), | ||
86 | }, | ||
87 | }; | ||
88 | module_platform_driver(pm8916_pon_driver); | ||
89 | |||
90 | MODULE_DESCRIPTION("pm8916 Power On driver"); | ||
91 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 102f95a09460..e9e749f87517 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c | |||
@@ -35,6 +35,7 @@ static void vexpress_reset_do(struct device *dev, const char *what) | |||
35 | } | 35 | } |
36 | 36 | ||
37 | static struct device *vexpress_power_off_device; | 37 | static struct device *vexpress_power_off_device; |
38 | static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0); | ||
38 | 39 | ||
39 | static void vexpress_power_off(void) | 40 | static void vexpress_power_off(void) |
40 | { | 41 | { |
@@ -99,10 +100,13 @@ static int _vexpress_register_restart_handler(struct device *dev) | |||
99 | int err; | 100 | int err; |
100 | 101 | ||
101 | vexpress_restart_device = dev; | 102 | vexpress_restart_device = dev; |
102 | err = register_restart_handler(&vexpress_restart_nb); | 103 | if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) { |
103 | if (err) { | 104 | err = register_restart_handler(&vexpress_restart_nb); |
104 | dev_err(dev, "cannot register restart handler (err=%d)\n", err); | 105 | if (err) { |
105 | return err; | 106 | dev_err(dev, "cannot register restart handler (err=%d)\n", err); |
107 | atomic_dec(&vexpress_restart_nb_refcnt); | ||
108 | return err; | ||
109 | } | ||
106 | } | 110 | } |
107 | device_create_file(dev, &dev_attr_active); | 111 | device_create_file(dev, &dev_attr_active); |
108 | 112 | ||
diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index c03e96e6a041..186901c96c01 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c | |||
@@ -51,6 +51,7 @@ static int zx_reboot_probe(struct platform_device *pdev) | |||
51 | 51 | ||
52 | np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); | 52 | np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); |
53 | pcu_base = of_iomap(np, 0); | 53 | pcu_base = of_iomap(np, 0); |
54 | of_node_put(np); | ||
54 | if (!pcu_base) { | 55 | if (!pcu_base) { |
55 | iounmap(base); | 56 | iounmap(base); |
56 | WARN(1, "failed to map pcu_base address"); | 57 | WARN(1, "failed to map pcu_base address"); |
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 428b426842f4..ff6dab0bf0dd 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig | |||
@@ -75,6 +75,17 @@ config BATTERY_88PM860X | |||
75 | help | 75 | help |
76 | Say Y here to enable battery monitor for Marvell 88PM860x chip. | 76 | Say Y here to enable battery monitor for Marvell 88PM860x chip. |
77 | 77 | ||
78 | config CHARGER_ADP5061 | ||
79 | tristate "ADP5061 battery charger driver" | ||
80 | depends on I2C | ||
81 | select REGMAP_I2C | ||
82 | help | ||
83 | Say Y here to enable support for the ADP5061 standalone battery | ||
84 | charger. | ||
85 | |||
86 | This driver can be built as a module. If so, the module will be | ||
87 | called adp5061. | ||
88 | |||
78 | config BATTERY_ACT8945A | 89 | config BATTERY_ACT8945A |
79 | tristate "Active-semi ACT8945A charger driver" | 90 | tristate "Active-semi ACT8945A charger driver" |
80 | depends on MFD_ACT8945A || COMPILE_TEST | 91 | depends on MFD_ACT8945A || COMPILE_TEST |
@@ -92,7 +103,7 @@ config BATTERY_CPCAP | |||
92 | 103 | ||
93 | config BATTERY_DS2760 | 104 | config BATTERY_DS2760 |
94 | tristate "DS2760 battery driver (HP iPAQ & others)" | 105 | tristate "DS2760 battery driver (HP iPAQ & others)" |
95 | depends on W1 && W1_SLAVE_DS2760 | 106 | depends on W1 |
96 | help | 107 | help |
97 | Say Y here to enable support for batteries with ds2760 chip. | 108 | Say Y here to enable support for batteries with ds2760 chip. |
98 | 109 | ||
@@ -624,4 +635,14 @@ config CHARGER_RT9455 | |||
624 | help | 635 | help |
625 | Say Y to enable support for Richtek RT9455 battery charger. | 636 | Say Y to enable support for Richtek RT9455 battery charger. |
626 | 637 | ||
638 | config CHARGER_CROS_USBPD | ||
639 | tristate "ChromeOS EC based USBPD charger" | ||
640 | depends on MFD_CROS_EC | ||
641 | default n | ||
642 | help | ||
643 | Say Y here to enable ChromeOS EC based USBPD charger | ||
644 | driver. This driver gets various bits of information about | ||
645 | what is connected to USB PD ports from the EC and converts | ||
646 | that into power_supply properties. | ||
647 | |||
627 | endif # POWER_SUPPLY | 648 | endif # POWER_SUPPLY |
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index e83aa843bcc6..a26b402c45d9 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o | |||
18 | obj-$(CONFIG_TEST_POWER) += test_power.o | 18 | obj-$(CONFIG_TEST_POWER) += test_power.o |
19 | 19 | ||
20 | obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o | 20 | obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o |
21 | obj-$(CONFIG_CHARGER_ADP5061) += adp5061.o | ||
21 | obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o | 22 | obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o |
22 | obj-$(CONFIG_BATTERY_AXP20X) += axp20x_battery.o | 23 | obj-$(CONFIG_BATTERY_AXP20X) += axp20x_battery.o |
23 | obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o | 24 | obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o |
@@ -83,3 +84,4 @@ obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o | |||
83 | obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o | 84 | obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o |
84 | obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o | 85 | obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o |
85 | obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o | 86 | obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o |
87 | obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o | ||
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index d9c6c7bedd85..02356f9b5f22 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c | |||
@@ -379,15 +379,13 @@ static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr) | |||
379 | */ | 379 | */ |
380 | static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample) | 380 | static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample) |
381 | { | 381 | { |
382 | struct timespec64 ts64; | 382 | time64_t now = ktime_get_boottime_seconds(); |
383 | struct ab8500_fg_avg_cap *avg = &di->avg_cap; | 383 | struct ab8500_fg_avg_cap *avg = &di->avg_cap; |
384 | 384 | ||
385 | getnstimeofday64(&ts64); | ||
386 | |||
387 | do { | 385 | do { |
388 | avg->sum += sample - avg->samples[avg->pos]; | 386 | avg->sum += sample - avg->samples[avg->pos]; |
389 | avg->samples[avg->pos] = sample; | 387 | avg->samples[avg->pos] = sample; |
390 | avg->time_stamps[avg->pos] = ts64.tv_sec; | 388 | avg->time_stamps[avg->pos] = now; |
391 | avg->pos++; | 389 | avg->pos++; |
392 | 390 | ||
393 | if (avg->pos == NBR_AVG_SAMPLES) | 391 | if (avg->pos == NBR_AVG_SAMPLES) |
@@ -400,7 +398,7 @@ static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample) | |||
400 | * Check the time stamp for each sample. If too old, | 398 | * Check the time stamp for each sample. If too old, |
401 | * replace with latest sample | 399 | * replace with latest sample |
402 | */ | 400 | */ |
403 | } while (ts64.tv_sec - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]); | 401 | } while (now - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]); |
404 | 402 | ||
405 | avg->avg = avg->sum / avg->nbr_samples; | 403 | avg->avg = avg->sum / avg->nbr_samples; |
406 | 404 | ||
@@ -439,14 +437,14 @@ static void ab8500_fg_clear_cap_samples(struct ab8500_fg *di) | |||
439 | static void ab8500_fg_fill_cap_sample(struct ab8500_fg *di, int sample) | 437 | static void ab8500_fg_fill_cap_sample(struct ab8500_fg *di, int sample) |
440 | { | 438 | { |
441 | int i; | 439 | int i; |
442 | struct timespec64 ts64; | 440 | time64_t now; |
443 | struct ab8500_fg_avg_cap *avg = &di->avg_cap; | 441 | struct ab8500_fg_avg_cap *avg = &di->avg_cap; |
444 | 442 | ||
445 | getnstimeofday64(&ts64); | 443 | now = ktime_get_boottime_seconds(); |
446 | 444 | ||
447 | for (i = 0; i < NBR_AVG_SAMPLES; i++) { | 445 | for (i = 0; i < NBR_AVG_SAMPLES; i++) { |
448 | avg->samples[i] = sample; | 446 | avg->samples[i] = sample; |
449 | avg->time_stamps[i] = ts64.tv_sec; | 447 | avg->time_stamps[i] = now; |
450 | } | 448 | } |
451 | 449 | ||
452 | avg->pos = 0; | 450 | avg->pos = 0; |
diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c new file mode 100644 index 000000000000..939fd3d8fb1a --- /dev/null +++ b/drivers/power/supply/adp5061.c | |||
@@ -0,0 +1,745 @@ | |||
1 | /* | ||
2 | * ADP5061 I2C Programmable Linear Battery Charger | ||
3 | * | ||
4 | * Copyright 2018 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/pm.h> | ||
15 | #include <linux/mod_devicetable.h> | ||
16 | #include <linux/power_supply.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/regmap.h> | ||
20 | |||
21 | /* ADP5061 registers definition */ | ||
22 | #define ADP5061_ID 0x00 | ||
23 | #define ADP5061_REV 0x01 | ||
24 | #define ADP5061_VINX_SET 0x02 | ||
25 | #define ADP5061_TERM_SET 0x03 | ||
26 | #define ADP5061_CHG_CURR 0x04 | ||
27 | #define ADP5061_VOLTAGE_TH 0x05 | ||
28 | #define ADP5061_TIMER_SET 0x06 | ||
29 | #define ADP5061_FUNC_SET_1 0x07 | ||
30 | #define ADP5061_FUNC_SET_2 0x08 | ||
31 | #define ADP5061_INT_EN 0x09 | ||
32 | #define ADP5061_INT_ACT 0x0A | ||
33 | #define ADP5061_CHG_STATUS_1 0x0B | ||
34 | #define ADP5061_CHG_STATUS_2 0x0C | ||
35 | #define ADP5061_FAULT 0x0D | ||
36 | #define ADP5061_BATTERY_SHORT 0x10 | ||
37 | #define ADP5061_IEND 0x11 | ||
38 | |||
39 | /* ADP5061_VINX_SET */ | ||
40 | #define ADP5061_VINX_SET_ILIM_MSK GENMASK(3, 0) | ||
41 | #define ADP5061_VINX_SET_ILIM_MODE(x) (((x) & 0x0F) << 0) | ||
42 | |||
43 | /* ADP5061_TERM_SET */ | ||
44 | #define ADP5061_TERM_SET_VTRM_MSK GENMASK(7, 2) | ||
45 | #define ADP5061_TERM_SET_VTRM_MODE(x) (((x) & 0x3F) << 2) | ||
46 | #define ADP5061_TERM_SET_CHG_VLIM_MSK GENMASK(1, 0) | ||
47 | #define ADP5061_TERM_SET_CHG_VLIM_MODE(x) (((x) & 0x03) << 0) | ||
48 | |||
49 | /* ADP5061_CHG_CURR */ | ||
50 | #define ADP5061_CHG_CURR_ICHG_MSK GENMASK(6, 2) | ||
51 | #define ADP5061_CHG_CURR_ICHG_MODE(x) (((x) & 0x1F) << 2) | ||
52 | #define ADP5061_CHG_CURR_ITRK_DEAD_MSK GENMASK(1, 0) | ||
53 | #define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x) (((x) & 0x03) << 0) | ||
54 | |||
55 | /* ADP5061_VOLTAGE_TH */ | ||
56 | #define ADP5061_VOLTAGE_TH_DIS_RCH_MSK BIT(7) | ||
57 | #define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x) (((x) & 0x01) << 7) | ||
58 | #define ADP5061_VOLTAGE_TH_VRCH_MSK GENMASK(6, 5) | ||
59 | #define ADP5061_VOLTAGE_TH_VRCH_MODE(x) (((x) & 0x03) << 5) | ||
60 | #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK GENMASK(4, 3) | ||
61 | #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x) (((x) & 0x03) << 3) | ||
62 | #define ADP5061_VOLTAGE_TH_VWEAK_MSK GENMASK(2, 0) | ||
63 | #define ADP5061_VOLTAGE_TH_VWEAK_MODE(x) (((x) & 0x07) << 0) | ||
64 | |||
65 | /* ADP5061_CHG_STATUS_1 */ | ||
66 | #define ADP5061_CHG_STATUS_1_VIN_OV(x) (((x) >> 7) & 0x1) | ||
67 | #define ADP5061_CHG_STATUS_1_VIN_OK(x) (((x) >> 6) & 0x1) | ||
68 | #define ADP5061_CHG_STATUS_1_VIN_ILIM(x) (((x) >> 5) & 0x1) | ||
69 | #define ADP5061_CHG_STATUS_1_THERM_LIM(x) (((x) >> 4) & 0x1) | ||
70 | #define ADP5061_CHG_STATUS_1_CHDONE(x) (((x) >> 3) & 0x1) | ||
71 | #define ADP5061_CHG_STATUS_1_CHG_STATUS(x) (((x) >> 0) & 0x7) | ||
72 | |||
73 | /* ADP5061_CHG_STATUS_2 */ | ||
74 | #define ADP5061_CHG_STATUS_2_THR_STATUS(x) (((x) >> 5) & 0x7) | ||
75 | #define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x) (((x) >> 3) & 0x1) | ||
76 | #define ADP5061_CHG_STATUS_2_BAT_STATUS(x) (((x) >> 0) & 0x7) | ||
77 | |||
78 | /* ADP5061_IEND */ | ||
79 | #define ADP5061_IEND_IEND_MSK GENMASK(7, 5) | ||
80 | #define ADP5061_IEND_IEND_MODE(x) (((x) & 0x07) << 5) | ||
81 | |||
82 | #define ADP5061_NO_BATTERY 0x01 | ||
83 | #define ADP5061_ICHG_MAX 1300 // mA | ||
84 | |||
85 | enum adp5061_chg_status { | ||
86 | ADP5061_CHG_OFF, | ||
87 | ADP5061_CHG_TRICKLE, | ||
88 | ADP5061_CHG_FAST_CC, | ||
89 | ADP5061_CHG_FAST_CV, | ||
90 | ADP5061_CHG_COMPLETE, | ||
91 | ADP5061_CHG_LDO_MODE, | ||
92 | ADP5061_CHG_TIMER_EXP, | ||
93 | ADP5061_CHG_BAT_DET, | ||
94 | }; | ||
95 | |||
96 | static const int adp5061_chg_type[4] = { | ||
97 | [ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE, | ||
98 | [ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE, | ||
99 | [ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST, | ||
100 | [ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST, | ||
101 | }; | ||
102 | |||
103 | static const int adp5061_vweak_th[8] = { | ||
104 | 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, | ||
105 | }; | ||
106 | |||
107 | static const int adp5061_prechg_current[4] = { | ||
108 | 5, 10, 20, 80, | ||
109 | }; | ||
110 | |||
111 | static const int adp5061_vmin[4] = { | ||
112 | 2000, 2500, 2600, 2900, | ||
113 | }; | ||
114 | |||
115 | static const int adp5061_const_chg_vmax[4] = { | ||
116 | 3200, 3400, 3700, 3800, | ||
117 | }; | ||
118 | |||
119 | static const int adp5061_const_ichg[24] = { | ||
120 | 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, | ||
121 | 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300, | ||
122 | }; | ||
123 | |||
124 | static const int adp5061_vmax[36] = { | ||
125 | 3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980, | ||
126 | 4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180, | ||
127 | 4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380, | ||
128 | 4400, 4420, 4440, 4460, 4480, 4500, | ||
129 | }; | ||
130 | |||
131 | static const int adp5061_in_current_lim[16] = { | ||
132 | 100, 150, 200, 250, 300, 400, 500, 600, 700, | ||
133 | 800, 900, 1000, 1200, 1500, 1800, 2100, | ||
134 | }; | ||
135 | |||
136 | static const int adp5061_iend[8] = { | ||
137 | 12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000, | ||
138 | }; | ||
139 | |||
140 | struct adp5061_state { | ||
141 | struct i2c_client *client; | ||
142 | struct regmap *regmap; | ||
143 | struct power_supply *psy; | ||
144 | }; | ||
145 | |||
146 | static int adp5061_get_array_index(const int *array, u8 size, int val) | ||
147 | { | ||
148 | int i; | ||
149 | |||
150 | for (i = 1; i < size; i++) { | ||
151 | if (val < array[i]) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | return i-1; | ||
156 | } | ||
157 | |||
158 | static int adp5061_get_status(struct adp5061_state *st, | ||
159 | u8 *status1, u8 *status2) | ||
160 | { | ||
161 | u8 buf[2]; | ||
162 | int ret; | ||
163 | |||
164 | /* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */ | ||
165 | ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1, | ||
166 | &buf[0], 2); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | |||
170 | *status1 = buf[0]; | ||
171 | *status2 = buf[1]; | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static int adp5061_get_input_current_limit(struct adp5061_state *st, | ||
177 | union power_supply_propval *val) | ||
178 | { | ||
179 | unsigned int regval; | ||
180 | int mode, ret; | ||
181 | |||
182 | ret = regmap_read(st->regmap, ADP5061_VINX_SET, ®val); | ||
183 | if (ret < 0) | ||
184 | return ret; | ||
185 | |||
186 | mode = ADP5061_VINX_SET_ILIM_MODE(regval); | ||
187 | val->intval = adp5061_in_current_lim[mode] * 1000; | ||
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static int adp5061_set_input_current_limit(struct adp5061_state *st, int val) | ||
193 | { | ||
194 | int index; | ||
195 | |||
196 | /* Convert from uA to mA */ | ||
197 | val /= 1000; | ||
198 | index = adp5061_get_array_index(adp5061_in_current_lim, | ||
199 | ARRAY_SIZE(adp5061_in_current_lim), | ||
200 | val); | ||
201 | if (index < 0) | ||
202 | return index; | ||
203 | |||
204 | return regmap_update_bits(st->regmap, ADP5061_VINX_SET, | ||
205 | ADP5061_VINX_SET_ILIM_MSK, | ||
206 | ADP5061_VINX_SET_ILIM_MODE(index)); | ||
207 | } | ||
208 | |||
209 | static int adp5061_set_min_voltage(struct adp5061_state *st, int val) | ||
210 | { | ||
211 | int index; | ||
212 | |||
213 | /* Convert from uV to mV */ | ||
214 | val /= 1000; | ||
215 | index = adp5061_get_array_index(adp5061_vmin, | ||
216 | ARRAY_SIZE(adp5061_vmin), | ||
217 | val); | ||
218 | if (index < 0) | ||
219 | return index; | ||
220 | |||
221 | return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, | ||
222 | ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK, | ||
223 | ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index)); | ||
224 | } | ||
225 | |||
226 | static int adp5061_get_min_voltage(struct adp5061_state *st, | ||
227 | union power_supply_propval *val) | ||
228 | { | ||
229 | unsigned int regval; | ||
230 | int ret; | ||
231 | |||
232 | ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); | ||
233 | if (ret < 0) | ||
234 | return ret; | ||
235 | |||
236 | regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3); | ||
237 | val->intval = adp5061_vmin[regval] * 1000; | ||
238 | |||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int adp5061_get_chg_volt_lim(struct adp5061_state *st, | ||
243 | union power_supply_propval *val) | ||
244 | { | ||
245 | unsigned int regval; | ||
246 | int mode, ret; | ||
247 | |||
248 | ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
251 | |||
252 | mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval); | ||
253 | val->intval = adp5061_const_chg_vmax[mode] * 1000; | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int adp5061_get_max_voltage(struct adp5061_state *st, | ||
259 | union power_supply_propval *val) | ||
260 | { | ||
261 | unsigned int regval; | ||
262 | int ret; | ||
263 | |||
264 | ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); | ||
265 | if (ret < 0) | ||
266 | return ret; | ||
267 | |||
268 | regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F; | ||
269 | if (regval >= ARRAY_SIZE(adp5061_vmax)) | ||
270 | regval = ARRAY_SIZE(adp5061_vmax) - 1; | ||
271 | |||
272 | val->intval = adp5061_vmax[regval] * 1000; | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static int adp5061_set_max_voltage(struct adp5061_state *st, int val) | ||
278 | { | ||
279 | int vmax_index; | ||
280 | |||
281 | /* Convert from uV to mV */ | ||
282 | val /= 1000; | ||
283 | if (val > 4500) | ||
284 | val = 4500; | ||
285 | |||
286 | vmax_index = adp5061_get_array_index(adp5061_vmax, | ||
287 | ARRAY_SIZE(adp5061_vmax), val); | ||
288 | if (vmax_index < 0) | ||
289 | return vmax_index; | ||
290 | |||
291 | vmax_index += 0x0F; | ||
292 | |||
293 | return regmap_update_bits(st->regmap, ADP5061_TERM_SET, | ||
294 | ADP5061_TERM_SET_VTRM_MSK, | ||
295 | ADP5061_TERM_SET_VTRM_MODE(vmax_index)); | ||
296 | } | ||
297 | |||
298 | static int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val) | ||
299 | { | ||
300 | int index; | ||
301 | |||
302 | /* Convert from uV to mV */ | ||
303 | val /= 1000; | ||
304 | index = adp5061_get_array_index(adp5061_const_chg_vmax, | ||
305 | ARRAY_SIZE(adp5061_const_chg_vmax), | ||
306 | val); | ||
307 | if (index < 0) | ||
308 | return index; | ||
309 | |||
310 | return regmap_update_bits(st->regmap, ADP5061_TERM_SET, | ||
311 | ADP5061_TERM_SET_CHG_VLIM_MSK, | ||
312 | ADP5061_TERM_SET_CHG_VLIM_MODE(index)); | ||
313 | } | ||
314 | |||
315 | static int adp5061_set_const_chg_current(struct adp5061_state *st, int val) | ||
316 | { | ||
317 | |||
318 | int index; | ||
319 | |||
320 | /* Convert from uA to mA */ | ||
321 | val /= 1000; | ||
322 | if (val > ADP5061_ICHG_MAX) | ||
323 | val = ADP5061_ICHG_MAX; | ||
324 | |||
325 | index = adp5061_get_array_index(adp5061_const_ichg, | ||
326 | ARRAY_SIZE(adp5061_const_ichg), | ||
327 | val); | ||
328 | if (index < 0) | ||
329 | return index; | ||
330 | |||
331 | return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, | ||
332 | ADP5061_CHG_CURR_ICHG_MSK, | ||
333 | ADP5061_CHG_CURR_ICHG_MODE(index)); | ||
334 | } | ||
335 | |||
336 | static int adp5061_get_const_chg_current(struct adp5061_state *st, | ||
337 | union power_supply_propval *val) | ||
338 | { | ||
339 | unsigned int regval; | ||
340 | int ret; | ||
341 | |||
342 | ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); | ||
343 | if (ret < 0) | ||
344 | return ret; | ||
345 | |||
346 | regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2); | ||
347 | if (regval >= ARRAY_SIZE(adp5061_const_ichg)) | ||
348 | regval = ARRAY_SIZE(adp5061_const_ichg) - 1; | ||
349 | |||
350 | val->intval = adp5061_const_ichg[regval] * 1000; | ||
351 | |||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | static int adp5061_get_prechg_current(struct adp5061_state *st, | ||
356 | union power_supply_propval *val) | ||
357 | { | ||
358 | unsigned int regval; | ||
359 | int ret; | ||
360 | |||
361 | ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); | ||
362 | if (ret < 0) | ||
363 | return ret; | ||
364 | |||
365 | regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK; | ||
366 | val->intval = adp5061_prechg_current[regval] * 1000; | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | static int adp5061_set_prechg_current(struct adp5061_state *st, int val) | ||
372 | { | ||
373 | int index; | ||
374 | |||
375 | /* Convert from uA to mA */ | ||
376 | val /= 1000; | ||
377 | index = adp5061_get_array_index(adp5061_prechg_current, | ||
378 | ARRAY_SIZE(adp5061_prechg_current), | ||
379 | val); | ||
380 | if (index < 0) | ||
381 | return index; | ||
382 | |||
383 | return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, | ||
384 | ADP5061_CHG_CURR_ITRK_DEAD_MSK, | ||
385 | ADP5061_CHG_CURR_ITRK_DEAD_MODE(index)); | ||
386 | } | ||
387 | |||
388 | static int adp5061_get_vweak_th(struct adp5061_state *st, | ||
389 | union power_supply_propval *val) | ||
390 | { | ||
391 | unsigned int regval; | ||
392 | int ret; | ||
393 | |||
394 | ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); | ||
395 | if (ret < 0) | ||
396 | return ret; | ||
397 | |||
398 | regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK; | ||
399 | val->intval = adp5061_vweak_th[regval] * 1000; | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int adp5061_set_vweak_th(struct adp5061_state *st, int val) | ||
405 | { | ||
406 | int index; | ||
407 | |||
408 | /* Convert from uV to mV */ | ||
409 | val /= 1000; | ||
410 | index = adp5061_get_array_index(adp5061_vweak_th, | ||
411 | ARRAY_SIZE(adp5061_vweak_th), | ||
412 | val); | ||
413 | if (index < 0) | ||
414 | return index; | ||
415 | |||
416 | return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, | ||
417 | ADP5061_VOLTAGE_TH_VWEAK_MSK, | ||
418 | ADP5061_VOLTAGE_TH_VWEAK_MODE(index)); | ||
419 | } | ||
420 | |||
421 | static int adp5061_get_chg_type(struct adp5061_state *st, | ||
422 | union power_supply_propval *val) | ||
423 | { | ||
424 | u8 status1, status2; | ||
425 | int chg_type, ret; | ||
426 | |||
427 | ret = adp5061_get_status(st, &status1, &status2); | ||
428 | if (ret < 0) | ||
429 | return ret; | ||
430 | |||
431 | chg_type = adp5061_chg_type[ADP5061_CHG_STATUS_1_CHG_STATUS(status1)]; | ||
432 | if (chg_type > ADP5061_CHG_FAST_CV) | ||
433 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
434 | else | ||
435 | val->intval = chg_type; | ||
436 | |||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | static int adp5061_get_charger_status(struct adp5061_state *st, | ||
441 | union power_supply_propval *val) | ||
442 | { | ||
443 | u8 status1, status2; | ||
444 | int ret; | ||
445 | |||
446 | ret = adp5061_get_status(st, &status1, &status2); | ||
447 | if (ret < 0) | ||
448 | return ret; | ||
449 | |||
450 | switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) { | ||
451 | case ADP5061_CHG_OFF: | ||
452 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
453 | break; | ||
454 | case ADP5061_CHG_TRICKLE: | ||
455 | case ADP5061_CHG_FAST_CC: | ||
456 | case ADP5061_CHG_FAST_CV: | ||
457 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
458 | break; | ||
459 | case ADP5061_CHG_COMPLETE: | ||
460 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
461 | break; | ||
462 | case ADP5061_CHG_TIMER_EXP: | ||
463 | /* The battery must be discharging if there is a charge fault */ | ||
464 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
465 | break; | ||
466 | default: | ||
467 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
468 | } | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | static int adp5061_get_battery_status(struct adp5061_state *st, | ||
474 | union power_supply_propval *val) | ||
475 | { | ||
476 | u8 status1, status2; | ||
477 | int ret; | ||
478 | |||
479 | ret = adp5061_get_status(st, &status1, &status2); | ||
480 | if (ret < 0) | ||
481 | return ret; | ||
482 | |||
483 | switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) { | ||
484 | case 0x0: /* Battery monitor off */ | ||
485 | case 0x1: /* No battery */ | ||
486 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; | ||
487 | break; | ||
488 | case 0x2: /* VBAT < VTRK */ | ||
489 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; | ||
490 | break; | ||
491 | case 0x3: /* VTRK < VBAT_SNS < VWEAK */ | ||
492 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
493 | break; | ||
494 | case 0x4: /* VBAT_SNS > VWEAK */ | ||
495 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | static int adp5061_get_termination_current(struct adp5061_state *st, | ||
503 | union power_supply_propval *val) | ||
504 | { | ||
505 | unsigned int regval; | ||
506 | int ret; | ||
507 | |||
508 | ret = regmap_read(st->regmap, ADP5061_IEND, ®val); | ||
509 | if (ret < 0) | ||
510 | return ret; | ||
511 | |||
512 | regval = (regval & ADP5061_IEND_IEND_MSK) >> 5; | ||
513 | val->intval = adp5061_iend[regval]; | ||
514 | |||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | static int adp5061_set_termination_current(struct adp5061_state *st, int val) | ||
519 | { | ||
520 | int index; | ||
521 | |||
522 | index = adp5061_get_array_index(adp5061_iend, | ||
523 | ARRAY_SIZE(adp5061_iend), | ||
524 | val); | ||
525 | if (index < 0) | ||
526 | return index; | ||
527 | |||
528 | return regmap_update_bits(st->regmap, ADP5061_IEND, | ||
529 | ADP5061_IEND_IEND_MSK, | ||
530 | ADP5061_IEND_IEND_MODE(index)); | ||
531 | } | ||
532 | |||
533 | static int adp5061_get_property(struct power_supply *psy, | ||
534 | enum power_supply_property psp, | ||
535 | union power_supply_propval *val) | ||
536 | { | ||
537 | struct adp5061_state *st = power_supply_get_drvdata(psy); | ||
538 | u8 status1, status2; | ||
539 | int mode, ret; | ||
540 | |||
541 | switch (psp) { | ||
542 | case POWER_SUPPLY_PROP_PRESENT: | ||
543 | ret = adp5061_get_status(st, &status1, &status2); | ||
544 | if (ret < 0) | ||
545 | return ret; | ||
546 | |||
547 | mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2); | ||
548 | if (mode == ADP5061_NO_BATTERY) | ||
549 | val->intval = 0; | ||
550 | else | ||
551 | val->intval = 1; | ||
552 | break; | ||
553 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
554 | return adp5061_get_chg_type(st, val); | ||
555 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
556 | /* This property is used to indicate the input current | ||
557 | * limit into VINx (ILIM) | ||
558 | */ | ||
559 | return adp5061_get_input_current_limit(st, val); | ||
560 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
561 | /* This property is used to indicate the termination | ||
562 | * voltage (VTRM) | ||
563 | */ | ||
564 | return adp5061_get_max_voltage(st, val); | ||
565 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
566 | /* | ||
567 | * This property is used to indicate the trickle to fast | ||
568 | * charge threshold (VTRK_DEAD) | ||
569 | */ | ||
570 | return adp5061_get_min_voltage(st, val); | ||
571 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: | ||
572 | /* This property is used to indicate the charging | ||
573 | * voltage limit (CHG_VLIM) | ||
574 | */ | ||
575 | return adp5061_get_chg_volt_lim(st, val); | ||
576 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: | ||
577 | /* | ||
578 | * This property is used to indicate the value of the constant | ||
579 | * current charge (ICHG) | ||
580 | */ | ||
581 | return adp5061_get_const_chg_current(st, val); | ||
582 | case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: | ||
583 | /* | ||
584 | * This property is used to indicate the value of the trickle | ||
585 | * and weak charge currents (ITRK_DEAD) | ||
586 | */ | ||
587 | return adp5061_get_prechg_current(st, val); | ||
588 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
589 | /* | ||
590 | * This property is used to set the VWEAK threshold | ||
591 | * bellow this value, weak charge mode is entered | ||
592 | * above this value, fast chargerge mode is entered | ||
593 | */ | ||
594 | return adp5061_get_vweak_th(st, val); | ||
595 | case POWER_SUPPLY_PROP_STATUS: | ||
596 | /* | ||
597 | * Indicate the charger status in relation to power | ||
598 | * supply status property | ||
599 | */ | ||
600 | return adp5061_get_charger_status(st, val); | ||
601 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | ||
602 | /* | ||
603 | * Indicate the battery status in relation to power | ||
604 | * supply capacity level property | ||
605 | */ | ||
606 | return adp5061_get_battery_status(st, val); | ||
607 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: | ||
608 | /* Indicate the values of the termination current */ | ||
609 | return adp5061_get_termination_current(st, val); | ||
610 | default: | ||
611 | return -EINVAL; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int adp5061_set_property(struct power_supply *psy, | ||
618 | enum power_supply_property psp, | ||
619 | const union power_supply_propval *val) | ||
620 | { | ||
621 | struct adp5061_state *st = power_supply_get_drvdata(psy); | ||
622 | |||
623 | switch (psp) { | ||
624 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
625 | return adp5061_set_input_current_limit(st, val->intval); | ||
626 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
627 | return adp5061_set_max_voltage(st, val->intval); | ||
628 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
629 | return adp5061_set_min_voltage(st, val->intval); | ||
630 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: | ||
631 | return adp5061_set_const_chg_vmax(st, val->intval); | ||
632 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: | ||
633 | return adp5061_set_const_chg_current(st, val->intval); | ||
634 | case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: | ||
635 | return adp5061_set_prechg_current(st, val->intval); | ||
636 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
637 | return adp5061_set_vweak_th(st, val->intval); | ||
638 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: | ||
639 | return adp5061_set_termination_current(st, val->intval); | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int adp5061_prop_writeable(struct power_supply *psy, | ||
648 | enum power_supply_property psp) | ||
649 | { | ||
650 | switch (psp) { | ||
651 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
652 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
653 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
654 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: | ||
655 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: | ||
656 | case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: | ||
657 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
658 | case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: | ||
659 | return 1; | ||
660 | default: | ||
661 | return 0; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | static enum power_supply_property adp5061_props[] = { | ||
666 | POWER_SUPPLY_PROP_PRESENT, | ||
667 | POWER_SUPPLY_PROP_CHARGE_TYPE, | ||
668 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, | ||
669 | POWER_SUPPLY_PROP_VOLTAGE_MAX, | ||
670 | POWER_SUPPLY_PROP_VOLTAGE_MIN, | ||
671 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, | ||
672 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, | ||
673 | POWER_SUPPLY_PROP_PRECHARGE_CURRENT, | ||
674 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
675 | POWER_SUPPLY_PROP_STATUS, | ||
676 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
677 | POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, | ||
678 | }; | ||
679 | |||
680 | static const struct regmap_config adp5061_regmap_config = { | ||
681 | .reg_bits = 8, | ||
682 | .val_bits = 8, | ||
683 | }; | ||
684 | |||
685 | static const struct power_supply_desc adp5061_desc = { | ||
686 | .name = "adp5061", | ||
687 | .type = POWER_SUPPLY_TYPE_USB, | ||
688 | .get_property = adp5061_get_property, | ||
689 | .set_property = adp5061_set_property, | ||
690 | .property_is_writeable = adp5061_prop_writeable, | ||
691 | .properties = adp5061_props, | ||
692 | .num_properties = ARRAY_SIZE(adp5061_props), | ||
693 | }; | ||
694 | |||
695 | static int adp5061_probe(struct i2c_client *client, | ||
696 | const struct i2c_device_id *id) | ||
697 | { | ||
698 | struct power_supply_config psy_cfg = {}; | ||
699 | struct adp5061_state *st; | ||
700 | |||
701 | st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); | ||
702 | if (!st) | ||
703 | return -ENOMEM; | ||
704 | |||
705 | st->client = client; | ||
706 | st->regmap = devm_regmap_init_i2c(client, | ||
707 | &adp5061_regmap_config); | ||
708 | if (IS_ERR(st->regmap)) { | ||
709 | dev_err(&client->dev, "Failed to initialize register map\n"); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | i2c_set_clientdata(client, st); | ||
714 | psy_cfg.drv_data = st; | ||
715 | |||
716 | st->psy = devm_power_supply_register(&client->dev, | ||
717 | &adp5061_desc, | ||
718 | &psy_cfg); | ||
719 | |||
720 | if (IS_ERR(st->psy)) { | ||
721 | dev_err(&client->dev, "Failed to register power supply\n"); | ||
722 | return PTR_ERR(st->psy); | ||
723 | } | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static const struct i2c_device_id adp5061_id[] = { | ||
729 | { "adp5061", 0}, | ||
730 | { } | ||
731 | }; | ||
732 | MODULE_DEVICE_TABLE(i2c, adp5061_id); | ||
733 | |||
734 | static struct i2c_driver adp5061_driver = { | ||
735 | .driver = { | ||
736 | .name = KBUILD_MODNAME, | ||
737 | }, | ||
738 | .probe = adp5061_probe, | ||
739 | .id_table = adp5061_id, | ||
740 | }; | ||
741 | module_i2c_driver(adp5061_driver); | ||
742 | |||
743 | MODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver"); | ||
744 | MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); | ||
745 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 44f70dcea61e..42001df4bd13 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c | |||
@@ -222,6 +222,7 @@ static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, | |||
222 | case 100000: | 222 | case 100000: |
223 | if (power->axp20x_id == AXP221_ID) | 223 | if (power->axp20x_id == AXP221_ID) |
224 | return -EINVAL; | 224 | return -EINVAL; |
225 | /* fall through */ | ||
225 | case 500000: | 226 | case 500000: |
226 | case 900000: | 227 | case 900000: |
227 | val = (900000 - intval) / 400000; | 228 | val = (900000 - intval) / 400000; |
diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 6e1bc14c3304..735658ee1c60 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c | |||
@@ -718,7 +718,7 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) | |||
718 | } | 718 | } |
719 | 719 | ||
720 | /* Determine charge current limit */ | 720 | /* Determine charge current limit */ |
721 | cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; | 721 | cc = (val & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; |
722 | cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; | 722 | cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; |
723 | info->cc = cc; | 723 | info->cc = cc; |
724 | 724 | ||
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index d44ed8e17c47..f022e1b550df 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * http://www.ti.com/product/bq27510-g1 | 26 | * http://www.ti.com/product/bq27510-g1 |
27 | * http://www.ti.com/product/bq27510-g2 | 27 | * http://www.ti.com/product/bq27510-g2 |
28 | * http://www.ti.com/product/bq27510-g3 | 28 | * http://www.ti.com/product/bq27510-g3 |
29 | * http://www.ti.com/product/bq27520-g4 | ||
30 | * http://www.ti.com/product/bq27520-g1 | 29 | * http://www.ti.com/product/bq27520-g1 |
31 | * http://www.ti.com/product/bq27520-g2 | 30 | * http://www.ti.com/product/bq27520-g2 |
32 | * http://www.ti.com/product/bq27520-g3 | 31 | * http://www.ti.com/product/bq27520-g3 |
@@ -40,7 +39,9 @@ | |||
40 | * http://www.ti.com/product/bq27545-g1 | 39 | * http://www.ti.com/product/bq27545-g1 |
41 | * http://www.ti.com/product/bq27421-g1 | 40 | * http://www.ti.com/product/bq27421-g1 |
42 | * http://www.ti.com/product/bq27425-g1 | 41 | * http://www.ti.com/product/bq27425-g1 |
42 | * http://www.ti.com/product/bq27426 | ||
43 | * http://www.ti.com/product/bq27411-g1 | 43 | * http://www.ti.com/product/bq27411-g1 |
44 | * http://www.ti.com/product/bq27441-g1 | ||
44 | * http://www.ti.com/product/bq27621-g1 | 45 | * http://www.ti.com/product/bq27621-g1 |
45 | */ | 46 | */ |
46 | 47 | ||
diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c new file mode 100644 index 000000000000..688a16bacfbb --- /dev/null +++ b/drivers/power/supply/cros_usbpd-charger.c | |||
@@ -0,0 +1,545 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Power supply driver for ChromeOS EC based USB PD Charger. | ||
4 | * | ||
5 | * Copyright (c) 2014 - 2018 Google, Inc | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/mfd/cros_ec.h> | ||
10 | #include <linux/mfd/cros_ec_commands.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/power_supply.h> | ||
13 | #include <linux/slab.h> | ||
14 | |||
15 | #define CHARGER_DIR_NAME "CROS_USBPD_CHARGER%d" | ||
16 | #define CHARGER_DIR_NAME_LENGTH sizeof(CHARGER_DIR_NAME) | ||
17 | #define CHARGER_CACHE_UPDATE_DELAY msecs_to_jiffies(500) | ||
18 | #define CHARGER_MANUFACTURER_MODEL_LENGTH 32 | ||
19 | |||
20 | #define DRV_NAME "cros-usbpd-charger" | ||
21 | |||
22 | struct port_data { | ||
23 | int port_number; | ||
24 | char name[CHARGER_DIR_NAME_LENGTH]; | ||
25 | char manufacturer[CHARGER_MANUFACTURER_MODEL_LENGTH]; | ||
26 | char model_name[CHARGER_MANUFACTURER_MODEL_LENGTH]; | ||
27 | struct power_supply *psy; | ||
28 | struct power_supply_desc psy_desc; | ||
29 | int psy_usb_type; | ||
30 | int psy_online; | ||
31 | int psy_status; | ||
32 | int psy_current_max; | ||
33 | int psy_voltage_max_design; | ||
34 | int psy_voltage_now; | ||
35 | int psy_power_max; | ||
36 | struct charger_data *charger; | ||
37 | unsigned long last_update; | ||
38 | }; | ||
39 | |||
40 | struct charger_data { | ||
41 | struct device *dev; | ||
42 | struct cros_ec_dev *ec_dev; | ||
43 | struct cros_ec_device *ec_device; | ||
44 | int num_charger_ports; | ||
45 | int num_registered_psy; | ||
46 | struct port_data *ports[EC_USB_PD_MAX_PORTS]; | ||
47 | struct notifier_block notifier; | ||
48 | }; | ||
49 | |||
50 | static enum power_supply_property cros_usbpd_charger_props[] = { | ||
51 | POWER_SUPPLY_PROP_ONLINE, | ||
52 | POWER_SUPPLY_PROP_STATUS, | ||
53 | POWER_SUPPLY_PROP_CURRENT_MAX, | ||
54 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
55 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
56 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
57 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
58 | POWER_SUPPLY_PROP_USB_TYPE | ||
59 | }; | ||
60 | |||
61 | static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { | ||
62 | POWER_SUPPLY_USB_TYPE_UNKNOWN, | ||
63 | POWER_SUPPLY_USB_TYPE_SDP, | ||
64 | POWER_SUPPLY_USB_TYPE_DCP, | ||
65 | POWER_SUPPLY_USB_TYPE_CDP, | ||
66 | POWER_SUPPLY_USB_TYPE_C, | ||
67 | POWER_SUPPLY_USB_TYPE_PD, | ||
68 | POWER_SUPPLY_USB_TYPE_PD_DRP, | ||
69 | POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID | ||
70 | }; | ||
71 | |||
72 | static int cros_usbpd_charger_ec_command(struct charger_data *charger, | ||
73 | unsigned int version, | ||
74 | unsigned int command, | ||
75 | void *outdata, | ||
76 | unsigned int outsize, | ||
77 | void *indata, | ||
78 | unsigned int insize) | ||
79 | { | ||
80 | struct cros_ec_dev *ec_dev = charger->ec_dev; | ||
81 | struct cros_ec_command *msg; | ||
82 | int ret; | ||
83 | |||
84 | msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); | ||
85 | if (!msg) | ||
86 | return -ENOMEM; | ||
87 | |||
88 | msg->version = version; | ||
89 | msg->command = ec_dev->cmd_offset + command; | ||
90 | msg->outsize = outsize; | ||
91 | msg->insize = insize; | ||
92 | |||
93 | if (outsize) | ||
94 | memcpy(msg->data, outdata, outsize); | ||
95 | |||
96 | ret = cros_ec_cmd_xfer_status(charger->ec_device, msg); | ||
97 | if (ret >= 0 && insize) | ||
98 | memcpy(indata, msg->data, insize); | ||
99 | |||
100 | kfree(msg); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static int cros_usbpd_charger_get_num_ports(struct charger_data *charger) | ||
105 | { | ||
106 | struct ec_response_usb_pd_ports resp; | ||
107 | int ret; | ||
108 | |||
109 | ret = cros_usbpd_charger_ec_command(charger, 0, EC_CMD_USB_PD_PORTS, | ||
110 | NULL, 0, &resp, sizeof(resp)); | ||
111 | if (ret < 0) { | ||
112 | dev_err(charger->dev, | ||
113 | "Unable to get the number or ports (err:0x%x)\n", ret); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | return resp.num_ports; | ||
118 | } | ||
119 | |||
120 | static int cros_usbpd_charger_get_discovery_info(struct port_data *port) | ||
121 | { | ||
122 | struct charger_data *charger = port->charger; | ||
123 | struct ec_params_usb_pd_discovery_entry resp; | ||
124 | struct ec_params_usb_pd_info_request req; | ||
125 | int ret; | ||
126 | |||
127 | req.port = port->port_number; | ||
128 | |||
129 | ret = cros_usbpd_charger_ec_command(charger, 0, | ||
130 | EC_CMD_USB_PD_DISCOVERY, | ||
131 | &req, sizeof(req), | ||
132 | &resp, sizeof(resp)); | ||
133 | if (ret < 0) { | ||
134 | dev_err(charger->dev, | ||
135 | "Unable to query discovery info (err:0x%x)\n", ret); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | dev_dbg(charger->dev, "Port %d: VID = 0x%x, PID=0x%x, PTYPE=0x%x\n", | ||
140 | port->port_number, resp.vid, resp.pid, resp.ptype); | ||
141 | |||
142 | snprintf(port->manufacturer, sizeof(port->manufacturer), "%x", | ||
143 | resp.vid); | ||
144 | snprintf(port->model_name, sizeof(port->model_name), "%x", resp.pid); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int cros_usbpd_charger_get_power_info(struct port_data *port) | ||
150 | { | ||
151 | struct charger_data *charger = port->charger; | ||
152 | struct ec_response_usb_pd_power_info resp; | ||
153 | struct ec_params_usb_pd_power_info req; | ||
154 | int last_psy_status, last_psy_usb_type; | ||
155 | struct device *dev = charger->dev; | ||
156 | int ret; | ||
157 | |||
158 | req.port = port->port_number; | ||
159 | ret = cros_usbpd_charger_ec_command(charger, 0, | ||
160 | EC_CMD_USB_PD_POWER_INFO, | ||
161 | &req, sizeof(req), | ||
162 | &resp, sizeof(resp)); | ||
163 | if (ret < 0) { | ||
164 | dev_err(dev, "Unable to query PD power info (err:0x%x)\n", ret); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | last_psy_status = port->psy_status; | ||
169 | last_psy_usb_type = port->psy_usb_type; | ||
170 | |||
171 | switch (resp.role) { | ||
172 | case USB_PD_PORT_POWER_DISCONNECTED: | ||
173 | port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
174 | port->psy_online = 0; | ||
175 | break; | ||
176 | case USB_PD_PORT_POWER_SOURCE: | ||
177 | port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
178 | port->psy_online = 0; | ||
179 | break; | ||
180 | case USB_PD_PORT_POWER_SINK: | ||
181 | port->psy_status = POWER_SUPPLY_STATUS_CHARGING; | ||
182 | port->psy_online = 1; | ||
183 | break; | ||
184 | case USB_PD_PORT_POWER_SINK_NOT_CHARGING: | ||
185 | port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
186 | port->psy_online = 1; | ||
187 | break; | ||
188 | default: | ||
189 | dev_err(dev, "Unknown role %d\n", resp.role); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | port->psy_voltage_max_design = resp.meas.voltage_max; | ||
194 | port->psy_voltage_now = resp.meas.voltage_now; | ||
195 | port->psy_current_max = resp.meas.current_max; | ||
196 | port->psy_power_max = resp.max_power; | ||
197 | |||
198 | switch (resp.type) { | ||
199 | case USB_CHG_TYPE_BC12_SDP: | ||
200 | case USB_CHG_TYPE_VBUS: | ||
201 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; | ||
202 | break; | ||
203 | case USB_CHG_TYPE_NONE: | ||
204 | /* | ||
205 | * For dual-role devices when we are a source, the firmware | ||
206 | * reports the type as NONE. Report such chargers as type | ||
207 | * USB_PD_DRP. | ||
208 | */ | ||
209 | if (resp.role == USB_PD_PORT_POWER_SOURCE && resp.dualrole) | ||
210 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD_DRP; | ||
211 | else | ||
212 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; | ||
213 | break; | ||
214 | case USB_CHG_TYPE_OTHER: | ||
215 | case USB_CHG_TYPE_PROPRIETARY: | ||
216 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID; | ||
217 | break; | ||
218 | case USB_CHG_TYPE_C: | ||
219 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_C; | ||
220 | break; | ||
221 | case USB_CHG_TYPE_BC12_DCP: | ||
222 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; | ||
223 | break; | ||
224 | case USB_CHG_TYPE_BC12_CDP: | ||
225 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; | ||
226 | break; | ||
227 | case USB_CHG_TYPE_PD: | ||
228 | if (resp.dualrole) | ||
229 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD_DRP; | ||
230 | else | ||
231 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD; | ||
232 | break; | ||
233 | case USB_CHG_TYPE_UNKNOWN: | ||
234 | /* | ||
235 | * While the EC is trying to determine the type of charger that | ||
236 | * has been plugged in, it will report the charger type as | ||
237 | * unknown. Additionally since the power capabilities are | ||
238 | * unknown, report the max current and voltage as zero. | ||
239 | */ | ||
240 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; | ||
241 | port->psy_voltage_max_design = 0; | ||
242 | port->psy_current_max = 0; | ||
243 | break; | ||
244 | default: | ||
245 | dev_err(dev, "Port %d: default case!\n", port->port_number); | ||
246 | port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; | ||
247 | } | ||
248 | |||
249 | port->psy_desc.type = POWER_SUPPLY_TYPE_USB; | ||
250 | |||
251 | dev_dbg(dev, | ||
252 | "Port %d: type=%d vmax=%d vnow=%d cmax=%d clim=%d pmax=%d\n", | ||
253 | port->port_number, resp.type, resp.meas.voltage_max, | ||
254 | resp.meas.voltage_now, resp.meas.current_max, | ||
255 | resp.meas.current_lim, resp.max_power); | ||
256 | |||
257 | /* | ||
258 | * If power supply type or status changed, explicitly call | ||
259 | * power_supply_changed. This results in udev event getting generated | ||
260 | * and allows user mode apps to react quicker instead of waiting for | ||
261 | * their next poll of power supply status. | ||
262 | */ | ||
263 | if (last_psy_usb_type != port->psy_usb_type || | ||
264 | last_psy_status != port->psy_status) | ||
265 | power_supply_changed(port->psy); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int cros_usbpd_charger_get_port_status(struct port_data *port, | ||
271 | bool ratelimit) | ||
272 | { | ||
273 | int ret; | ||
274 | |||
275 | if (ratelimit && | ||
276 | time_is_after_jiffies(port->last_update + | ||
277 | CHARGER_CACHE_UPDATE_DELAY)) | ||
278 | return 0; | ||
279 | |||
280 | ret = cros_usbpd_charger_get_power_info(port); | ||
281 | if (ret < 0) | ||
282 | return ret; | ||
283 | |||
284 | ret = cros_usbpd_charger_get_discovery_info(port); | ||
285 | port->last_update = jiffies; | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static void cros_usbpd_charger_power_changed(struct power_supply *psy) | ||
291 | { | ||
292 | struct port_data *port = power_supply_get_drvdata(psy); | ||
293 | struct charger_data *charger = port->charger; | ||
294 | int i; | ||
295 | |||
296 | for (i = 0; i < charger->num_registered_psy; i++) | ||
297 | cros_usbpd_charger_get_port_status(charger->ports[i], false); | ||
298 | } | ||
299 | |||
300 | static int cros_usbpd_charger_get_prop(struct power_supply *psy, | ||
301 | enum power_supply_property psp, | ||
302 | union power_supply_propval *val) | ||
303 | { | ||
304 | struct port_data *port = power_supply_get_drvdata(psy); | ||
305 | struct charger_data *charger = port->charger; | ||
306 | struct cros_ec_device *ec_device = charger->ec_device; | ||
307 | struct device *dev = charger->dev; | ||
308 | int ret; | ||
309 | |||
310 | /* Only refresh ec_port_status for dynamic properties */ | ||
311 | switch (psp) { | ||
312 | case POWER_SUPPLY_PROP_ONLINE: | ||
313 | /* | ||
314 | * If mkbp_event_supported, then we can be assured that | ||
315 | * the driver's state for the online property is consistent | ||
316 | * with the hardware. However, if we aren't event driven, | ||
317 | * the optimization before to skip an ec_port_status get | ||
318 | * and only returned cached values of the online property will | ||
319 | * cause a delay in detecting a cable attach until one of the | ||
320 | * other properties are read. | ||
321 | * | ||
322 | * Allow an ec_port_status refresh for online property check | ||
323 | * if we're not already online to check for plug events if | ||
324 | * not mkbp_event_supported. | ||
325 | */ | ||
326 | if (ec_device->mkbp_event_supported || port->psy_online) | ||
327 | break; | ||
328 | /* fall through */ | ||
329 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
330 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
331 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
332 | ret = cros_usbpd_charger_get_port_status(port, true); | ||
333 | if (ret < 0) { | ||
334 | dev_err(dev, "Failed to get port status (err:0x%x)\n", | ||
335 | ret); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | break; | ||
339 | default: | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | switch (psp) { | ||
344 | case POWER_SUPPLY_PROP_ONLINE: | ||
345 | val->intval = port->psy_online; | ||
346 | break; | ||
347 | case POWER_SUPPLY_PROP_STATUS: | ||
348 | val->intval = port->psy_status; | ||
349 | break; | ||
350 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
351 | val->intval = port->psy_current_max * 1000; | ||
352 | break; | ||
353 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
354 | val->intval = port->psy_voltage_max_design * 1000; | ||
355 | break; | ||
356 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
357 | val->intval = port->psy_voltage_now * 1000; | ||
358 | break; | ||
359 | case POWER_SUPPLY_PROP_USB_TYPE: | ||
360 | val->intval = port->psy_usb_type; | ||
361 | break; | ||
362 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
363 | val->strval = port->model_name; | ||
364 | break; | ||
365 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
366 | val->strval = port->manufacturer; | ||
367 | break; | ||
368 | default: | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int cros_usbpd_charger_ec_event(struct notifier_block *nb, | ||
376 | unsigned long queued_during_suspend, | ||
377 | void *_notify) | ||
378 | { | ||
379 | struct cros_ec_device *ec_device; | ||
380 | struct charger_data *charger; | ||
381 | struct device *dev; | ||
382 | u32 host_event; | ||
383 | |||
384 | charger = container_of(nb, struct charger_data, notifier); | ||
385 | ec_device = charger->ec_device; | ||
386 | dev = charger->dev; | ||
387 | |||
388 | host_event = cros_ec_get_host_event(ec_device); | ||
389 | if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) { | ||
390 | cros_usbpd_charger_power_changed(charger->ports[0]->psy); | ||
391 | return NOTIFY_OK; | ||
392 | } else { | ||
393 | return NOTIFY_DONE; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | static void cros_usbpd_charger_unregister_notifier(void *data) | ||
398 | { | ||
399 | struct charger_data *charger = data; | ||
400 | struct cros_ec_device *ec_device = charger->ec_device; | ||
401 | |||
402 | blocking_notifier_chain_unregister(&ec_device->event_notifier, | ||
403 | &charger->notifier); | ||
404 | } | ||
405 | |||
406 | static int cros_usbpd_charger_probe(struct platform_device *pd) | ||
407 | { | ||
408 | struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); | ||
409 | struct cros_ec_device *ec_device = ec_dev->ec_dev; | ||
410 | struct power_supply_desc *psy_desc; | ||
411 | struct device *dev = &pd->dev; | ||
412 | struct charger_data *charger; | ||
413 | struct power_supply *psy; | ||
414 | struct port_data *port; | ||
415 | int ret = -EINVAL; | ||
416 | int i; | ||
417 | |||
418 | charger = devm_kzalloc(dev, sizeof(struct charger_data), | ||
419 | GFP_KERNEL); | ||
420 | if (!charger) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | charger->dev = dev; | ||
424 | charger->ec_dev = ec_dev; | ||
425 | charger->ec_device = ec_device; | ||
426 | |||
427 | platform_set_drvdata(pd, charger); | ||
428 | |||
429 | charger->num_charger_ports = cros_usbpd_charger_get_num_ports(charger); | ||
430 | if (charger->num_charger_ports <= 0) { | ||
431 | /* | ||
432 | * This can happen on a system that doesn't support USB PD. | ||
433 | * Log a message, but no need to warn. | ||
434 | */ | ||
435 | dev_info(dev, "No charging ports found\n"); | ||
436 | ret = -ENODEV; | ||
437 | goto fail_nowarn; | ||
438 | } | ||
439 | |||
440 | for (i = 0; i < charger->num_charger_ports; i++) { | ||
441 | struct power_supply_config psy_cfg = {}; | ||
442 | |||
443 | port = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL); | ||
444 | if (!port) { | ||
445 | ret = -ENOMEM; | ||
446 | goto fail; | ||
447 | } | ||
448 | |||
449 | port->charger = charger; | ||
450 | port->port_number = i; | ||
451 | sprintf(port->name, CHARGER_DIR_NAME, i); | ||
452 | |||
453 | psy_desc = &port->psy_desc; | ||
454 | psy_desc->name = port->name; | ||
455 | psy_desc->type = POWER_SUPPLY_TYPE_USB; | ||
456 | psy_desc->get_property = cros_usbpd_charger_get_prop; | ||
457 | psy_desc->external_power_changed = | ||
458 | cros_usbpd_charger_power_changed; | ||
459 | psy_desc->properties = cros_usbpd_charger_props; | ||
460 | psy_desc->num_properties = | ||
461 | ARRAY_SIZE(cros_usbpd_charger_props); | ||
462 | psy_desc->usb_types = cros_usbpd_charger_usb_types; | ||
463 | psy_desc->num_usb_types = | ||
464 | ARRAY_SIZE(cros_usbpd_charger_usb_types); | ||
465 | psy_cfg.drv_data = port; | ||
466 | |||
467 | psy = devm_power_supply_register_no_ws(dev, psy_desc, | ||
468 | &psy_cfg); | ||
469 | if (IS_ERR(psy)) { | ||
470 | dev_err(dev, "Failed to register power supply\n"); | ||
471 | continue; | ||
472 | } | ||
473 | port->psy = psy; | ||
474 | |||
475 | charger->ports[charger->num_registered_psy++] = port; | ||
476 | } | ||
477 | |||
478 | if (!charger->num_registered_psy) { | ||
479 | ret = -ENODEV; | ||
480 | dev_err(dev, "No power supplies registered\n"); | ||
481 | goto fail; | ||
482 | } | ||
483 | |||
484 | if (ec_device->mkbp_event_supported) { | ||
485 | /* Get PD events from the EC */ | ||
486 | charger->notifier.notifier_call = cros_usbpd_charger_ec_event; | ||
487 | ret = blocking_notifier_chain_register( | ||
488 | &ec_device->event_notifier, | ||
489 | &charger->notifier); | ||
490 | if (ret < 0) { | ||
491 | dev_warn(dev, "failed to register notifier\n"); | ||
492 | } else { | ||
493 | ret = devm_add_action_or_reset(dev, | ||
494 | cros_usbpd_charger_unregister_notifier, | ||
495 | charger); | ||
496 | if (ret < 0) | ||
497 | goto fail; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | return 0; | ||
502 | |||
503 | fail: | ||
504 | WARN(1, "%s: Failing probe (err:0x%x)\n", dev_name(dev), ret); | ||
505 | |||
506 | fail_nowarn: | ||
507 | dev_info(dev, "Failing probe (err:0x%x)\n", ret); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | #ifdef CONFIG_PM_SLEEP | ||
512 | static int cros_usbpd_charger_resume(struct device *dev) | ||
513 | { | ||
514 | struct charger_data *charger = dev_get_drvdata(dev); | ||
515 | int i; | ||
516 | |||
517 | if (!charger) | ||
518 | return 0; | ||
519 | |||
520 | for (i = 0; i < charger->num_registered_psy; i++) { | ||
521 | power_supply_changed(charger->ports[i]->psy); | ||
522 | charger->ports[i]->last_update = | ||
523 | jiffies - CHARGER_CACHE_UPDATE_DELAY; | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | #endif | ||
529 | |||
530 | static SIMPLE_DEV_PM_OPS(cros_usbpd_charger_pm_ops, NULL, | ||
531 | cros_usbpd_charger_resume); | ||
532 | |||
533 | static struct platform_driver cros_usbpd_charger_driver = { | ||
534 | .driver = { | ||
535 | .name = DRV_NAME, | ||
536 | .pm = &cros_usbpd_charger_pm_ops, | ||
537 | }, | ||
538 | .probe = cros_usbpd_charger_probe | ||
539 | }; | ||
540 | |||
541 | module_platform_driver(cros_usbpd_charger_driver); | ||
542 | |||
543 | MODULE_LICENSE("GPL"); | ||
544 | MODULE_DESCRIPTION("ChromeOS EC USBPD charger"); | ||
545 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c index ae180dc929c9..11bed88a89fa 100644 --- a/drivers/power/supply/ds2760_battery.c +++ b/drivers/power/supply/ds2760_battery.c | |||
@@ -27,9 +27,64 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/power_supply.h> | 29 | #include <linux/power_supply.h> |
30 | 30 | #include <linux/suspend.h> | |
31 | #include <linux/w1.h> | 31 | #include <linux/w1.h> |
32 | #include "../../w1/slaves/w1_ds2760.h" | 32 | #include <linux/of.h> |
33 | |||
34 | static unsigned int cache_time = 1000; | ||
35 | module_param(cache_time, uint, 0644); | ||
36 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | ||
37 | |||
38 | static bool pmod_enabled; | ||
39 | module_param(pmod_enabled, bool, 0644); | ||
40 | MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); | ||
41 | |||
42 | static unsigned int rated_capacity; | ||
43 | module_param(rated_capacity, uint, 0644); | ||
44 | MODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index"); | ||
45 | |||
46 | static unsigned int current_accum; | ||
47 | module_param(current_accum, uint, 0644); | ||
48 | MODULE_PARM_DESC(current_accum, "current accumulator value"); | ||
49 | |||
50 | #define W1_FAMILY_DS2760 0x30 | ||
51 | |||
52 | /* Known commands to the DS2760 chip */ | ||
53 | #define W1_DS2760_SWAP 0xAA | ||
54 | #define W1_DS2760_READ_DATA 0x69 | ||
55 | #define W1_DS2760_WRITE_DATA 0x6C | ||
56 | #define W1_DS2760_COPY_DATA 0x48 | ||
57 | #define W1_DS2760_RECALL_DATA 0xB8 | ||
58 | #define W1_DS2760_LOCK 0x6A | ||
59 | |||
60 | /* Number of valid register addresses */ | ||
61 | #define DS2760_DATA_SIZE 0x40 | ||
62 | |||
63 | #define DS2760_PROTECTION_REG 0x00 | ||
64 | |||
65 | #define DS2760_STATUS_REG 0x01 | ||
66 | #define DS2760_STATUS_IE (1 << 2) | ||
67 | #define DS2760_STATUS_SWEN (1 << 3) | ||
68 | #define DS2760_STATUS_RNAOP (1 << 4) | ||
69 | #define DS2760_STATUS_PMOD (1 << 5) | ||
70 | |||
71 | #define DS2760_EEPROM_REG 0x07 | ||
72 | #define DS2760_SPECIAL_FEATURE_REG 0x08 | ||
73 | #define DS2760_VOLTAGE_MSB 0x0c | ||
74 | #define DS2760_VOLTAGE_LSB 0x0d | ||
75 | #define DS2760_CURRENT_MSB 0x0e | ||
76 | #define DS2760_CURRENT_LSB 0x0f | ||
77 | #define DS2760_CURRENT_ACCUM_MSB 0x10 | ||
78 | #define DS2760_CURRENT_ACCUM_LSB 0x11 | ||
79 | #define DS2760_TEMP_MSB 0x18 | ||
80 | #define DS2760_TEMP_LSB 0x19 | ||
81 | #define DS2760_EEPROM_BLOCK0 0x20 | ||
82 | #define DS2760_ACTIVE_FULL 0x20 | ||
83 | #define DS2760_EEPROM_BLOCK1 0x30 | ||
84 | #define DS2760_STATUS_WRITE_REG 0x31 | ||
85 | #define DS2760_RATED_CAPACITY 0x32 | ||
86 | #define DS2760_CURRENT_OFFSET_BIAS 0x33 | ||
87 | #define DS2760_ACTIVE_EMPTY 0x3b | ||
33 | 88 | ||
34 | struct ds2760_device_info { | 89 | struct ds2760_device_info { |
35 | struct device *dev; | 90 | struct device *dev; |
@@ -55,28 +110,113 @@ struct ds2760_device_info { | |||
55 | int full_counter; | 110 | int full_counter; |
56 | struct power_supply *bat; | 111 | struct power_supply *bat; |
57 | struct power_supply_desc bat_desc; | 112 | struct power_supply_desc bat_desc; |
58 | struct device *w1_dev; | ||
59 | struct workqueue_struct *monitor_wqueue; | 113 | struct workqueue_struct *monitor_wqueue; |
60 | struct delayed_work monitor_work; | 114 | struct delayed_work monitor_work; |
61 | struct delayed_work set_charged_work; | 115 | struct delayed_work set_charged_work; |
116 | struct notifier_block pm_notifier; | ||
62 | }; | 117 | }; |
63 | 118 | ||
64 | static unsigned int cache_time = 1000; | 119 | static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, |
65 | module_param(cache_time, uint, 0644); | 120 | int io) |
66 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | 121 | { |
122 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
67 | 123 | ||
68 | static bool pmod_enabled; | 124 | if (!dev) |
69 | module_param(pmod_enabled, bool, 0644); | 125 | return 0; |
70 | MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); | ||
71 | 126 | ||
72 | static unsigned int rated_capacity; | 127 | mutex_lock(&sl->master->bus_mutex); |
73 | module_param(rated_capacity, uint, 0644); | ||
74 | MODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index"); | ||
75 | 128 | ||
76 | static unsigned int current_accum; | 129 | if (addr > DS2760_DATA_SIZE || addr < 0) { |
77 | module_param(current_accum, uint, 0644); | 130 | count = 0; |
78 | MODULE_PARM_DESC(current_accum, "current accumulator value"); | 131 | goto out; |
132 | } | ||
133 | if (addr + count > DS2760_DATA_SIZE) | ||
134 | count = DS2760_DATA_SIZE - addr; | ||
135 | |||
136 | if (!w1_reset_select_slave(sl)) { | ||
137 | if (!io) { | ||
138 | w1_write_8(sl->master, W1_DS2760_READ_DATA); | ||
139 | w1_write_8(sl->master, addr); | ||
140 | count = w1_read_block(sl->master, buf, count); | ||
141 | } else { | ||
142 | w1_write_8(sl->master, W1_DS2760_WRITE_DATA); | ||
143 | w1_write_8(sl->master, addr); | ||
144 | w1_write_block(sl->master, buf, count); | ||
145 | /* XXX w1_write_block returns void, not n_written */ | ||
146 | } | ||
147 | } | ||
148 | |||
149 | out: | ||
150 | mutex_unlock(&sl->master->bus_mutex); | ||
151 | |||
152 | return count; | ||
153 | } | ||
154 | |||
155 | static int w1_ds2760_read(struct device *dev, | ||
156 | char *buf, int addr, | ||
157 | size_t count) | ||
158 | { | ||
159 | return w1_ds2760_io(dev, buf, addr, count, 0); | ||
160 | } | ||
161 | |||
162 | static int w1_ds2760_write(struct device *dev, | ||
163 | char *buf, | ||
164 | int addr, size_t count) | ||
165 | { | ||
166 | return w1_ds2760_io(dev, buf, addr, count, 1); | ||
167 | } | ||
168 | |||
169 | static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd) | ||
170 | { | ||
171 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
172 | |||
173 | if (!dev) | ||
174 | return -EINVAL; | ||
175 | |||
176 | mutex_lock(&sl->master->bus_mutex); | ||
177 | |||
178 | if (w1_reset_select_slave(sl) == 0) { | ||
179 | w1_write_8(sl->master, cmd); | ||
180 | w1_write_8(sl->master, addr); | ||
181 | } | ||
182 | |||
183 | mutex_unlock(&sl->master->bus_mutex); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int w1_ds2760_store_eeprom(struct device *dev, int addr) | ||
188 | { | ||
189 | return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA); | ||
190 | } | ||
191 | |||
192 | static int w1_ds2760_recall_eeprom(struct device *dev, int addr) | ||
193 | { | ||
194 | return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA); | ||
195 | } | ||
196 | |||
197 | static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, | ||
198 | struct bin_attribute *bin_attr, char *buf, | ||
199 | loff_t off, size_t count) | ||
200 | { | ||
201 | struct device *dev = container_of(kobj, struct device, kobj); | ||
202 | return w1_ds2760_read(dev, buf, off, count); | ||
203 | } | ||
204 | |||
205 | static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE); | ||
206 | |||
207 | static struct bin_attribute *w1_ds2760_bin_attrs[] = { | ||
208 | &bin_attr_w1_slave, | ||
209 | NULL, | ||
210 | }; | ||
211 | |||
212 | static const struct attribute_group w1_ds2760_group = { | ||
213 | .bin_attrs = w1_ds2760_bin_attrs, | ||
214 | }; | ||
79 | 215 | ||
216 | static const struct attribute_group *w1_ds2760_groups[] = { | ||
217 | &w1_ds2760_group, | ||
218 | NULL, | ||
219 | }; | ||
80 | /* Some batteries have their rated capacity stored a N * 10 mAh, while | 220 | /* Some batteries have their rated capacity stored a N * 10 mAh, while |
81 | * others use an index into this table. */ | 221 | * others use an index into this table. */ |
82 | static int rated_capacities[] = { | 222 | static int rated_capacities[] = { |
@@ -138,10 +278,10 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di) | |||
138 | count = DS2760_TEMP_LSB - start + 1; | 278 | count = DS2760_TEMP_LSB - start + 1; |
139 | } | 279 | } |
140 | 280 | ||
141 | ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); | 281 | ret = w1_ds2760_read(di->dev, di->raw + start, start, count); |
142 | if (ret != count) { | 282 | if (ret != count) { |
143 | dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", | 283 | dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", |
144 | di->w1_dev); | 284 | di->dev); |
145 | return 1; | 285 | return 1; |
146 | } | 286 | } |
147 | 287 | ||
@@ -242,7 +382,7 @@ static void ds2760_battery_set_current_accum(struct ds2760_device_info *di, | |||
242 | acr[0] = acr_val >> 8; | 382 | acr[0] = acr_val >> 8; |
243 | acr[1] = acr_val & 0xff; | 383 | acr[1] = acr_val & 0xff; |
244 | 384 | ||
245 | if (w1_ds2760_write(di->w1_dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2) | 385 | if (w1_ds2760_write(di->dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2) |
246 | dev_warn(di->dev, "ACR write failed\n"); | 386 | dev_warn(di->dev, "ACR write failed\n"); |
247 | } | 387 | } |
248 | 388 | ||
@@ -297,9 +437,9 @@ static void ds2760_battery_write_status(struct ds2760_device_info *di, | |||
297 | if (status == di->raw[DS2760_STATUS_REG]) | 437 | if (status == di->raw[DS2760_STATUS_REG]) |
298 | return; | 438 | return; |
299 | 439 | ||
300 | w1_ds2760_write(di->w1_dev, &status, DS2760_STATUS_WRITE_REG, 1); | 440 | w1_ds2760_write(di->dev, &status, DS2760_STATUS_WRITE_REG, 1); |
301 | w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 441 | w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
302 | w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 442 | w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
303 | } | 443 | } |
304 | 444 | ||
305 | static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, | 445 | static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, |
@@ -308,9 +448,9 @@ static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, | |||
308 | if (rated_capacity == di->raw[DS2760_RATED_CAPACITY]) | 448 | if (rated_capacity == di->raw[DS2760_RATED_CAPACITY]) |
309 | return; | 449 | return; |
310 | 450 | ||
311 | w1_ds2760_write(di->w1_dev, &rated_capacity, DS2760_RATED_CAPACITY, 1); | 451 | w1_ds2760_write(di->dev, &rated_capacity, DS2760_RATED_CAPACITY, 1); |
312 | w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 452 | w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
313 | w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 453 | w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
314 | } | 454 | } |
315 | 455 | ||
316 | static void ds2760_battery_write_active_full(struct ds2760_device_info *di, | 456 | static void ds2760_battery_write_active_full(struct ds2760_device_info *di, |
@@ -325,9 +465,9 @@ static void ds2760_battery_write_active_full(struct ds2760_device_info *di, | |||
325 | tmp[1] == di->raw[DS2760_ACTIVE_FULL + 1]) | 465 | tmp[1] == di->raw[DS2760_ACTIVE_FULL + 1]) |
326 | return; | 466 | return; |
327 | 467 | ||
328 | w1_ds2760_write(di->w1_dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp)); | 468 | w1_ds2760_write(di->dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp)); |
329 | w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0); | 469 | w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK0); |
330 | w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0); | 470 | w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK0); |
331 | 471 | ||
332 | /* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL | 472 | /* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL |
333 | * values won't be read back by ds2760_battery_read_status() */ | 473 | * values won't be read back by ds2760_battery_read_status() */ |
@@ -383,9 +523,9 @@ static void ds2760_battery_set_charged_work(struct work_struct *work) | |||
383 | 523 | ||
384 | dev_dbg(di->dev, "%s: bias = %d\n", __func__, bias); | 524 | dev_dbg(di->dev, "%s: bias = %d\n", __func__, bias); |
385 | 525 | ||
386 | w1_ds2760_write(di->w1_dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1); | 526 | w1_ds2760_write(di->dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1); |
387 | w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 527 | w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
388 | w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); | 528 | w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); |
389 | 529 | ||
390 | /* Write to the di->raw[] buffer directly - the CURRENT_OFFSET_BIAS | 530 | /* Write to the di->raw[] buffer directly - the CURRENT_OFFSET_BIAS |
391 | * value won't be read back by ds2760_battery_read_status() */ | 531 | * value won't be read back by ds2760_battery_read_status() */ |
@@ -504,24 +644,55 @@ static enum power_supply_property ds2760_battery_props[] = { | |||
504 | POWER_SUPPLY_PROP_CAPACITY, | 644 | POWER_SUPPLY_PROP_CAPACITY, |
505 | }; | 645 | }; |
506 | 646 | ||
507 | static int ds2760_battery_probe(struct platform_device *pdev) | 647 | static int ds2760_pm_notifier(struct notifier_block *notifier, |
648 | unsigned long pm_event, | ||
649 | void *unused) | ||
650 | { | ||
651 | struct ds2760_device_info *di = | ||
652 | container_of(notifier, struct ds2760_device_info, pm_notifier); | ||
653 | |||
654 | switch (pm_event) { | ||
655 | case PM_HIBERNATION_PREPARE: | ||
656 | case PM_SUSPEND_PREPARE: | ||
657 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
658 | break; | ||
659 | |||
660 | case PM_POST_RESTORE: | ||
661 | case PM_POST_HIBERNATION: | ||
662 | case PM_POST_SUSPEND: | ||
663 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
664 | power_supply_changed(di->bat); | ||
665 | mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); | ||
666 | |||
667 | break; | ||
668 | |||
669 | case PM_RESTORE_PREPARE: | ||
670 | default: | ||
671 | break; | ||
672 | } | ||
673 | |||
674 | return NOTIFY_DONE; | ||
675 | } | ||
676 | |||
677 | static int w1_ds2760_add_slave(struct w1_slave *sl) | ||
508 | { | 678 | { |
509 | struct power_supply_config psy_cfg = {}; | 679 | struct power_supply_config psy_cfg = {}; |
510 | char status; | ||
511 | int retval = 0; | ||
512 | struct ds2760_device_info *di; | 680 | struct ds2760_device_info *di; |
681 | struct device *dev = &sl->dev; | ||
682 | int retval = 0; | ||
683 | char name[32]; | ||
684 | char status; | ||
513 | 685 | ||
514 | di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); | 686 | di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); |
515 | if (!di) { | 687 | if (!di) { |
516 | retval = -ENOMEM; | 688 | retval = -ENOMEM; |
517 | goto di_alloc_failed; | 689 | goto di_alloc_failed; |
518 | } | 690 | } |
519 | 691 | ||
520 | platform_set_drvdata(pdev, di); | 692 | snprintf(name, sizeof(name), "ds2760-battery.%d", dev->id); |
521 | 693 | ||
522 | di->dev = &pdev->dev; | 694 | di->dev = dev; |
523 | di->w1_dev = pdev->dev.parent; | 695 | di->bat_desc.name = name; |
524 | di->bat_desc.name = dev_name(&pdev->dev); | ||
525 | di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; | 696 | di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; |
526 | di->bat_desc.properties = ds2760_battery_props; | 697 | di->bat_desc.properties = ds2760_battery_props; |
527 | di->bat_desc.num_properties = ARRAY_SIZE(ds2760_battery_props); | 698 | di->bat_desc.num_properties = ARRAY_SIZE(ds2760_battery_props); |
@@ -533,10 +704,30 @@ static int ds2760_battery_probe(struct platform_device *pdev) | |||
533 | di->bat_desc.external_power_changed = | 704 | di->bat_desc.external_power_changed = |
534 | ds2760_battery_external_power_changed; | 705 | ds2760_battery_external_power_changed; |
535 | 706 | ||
536 | psy_cfg.drv_data = di; | 707 | psy_cfg.drv_data = di; |
708 | |||
709 | if (dev->of_node) { | ||
710 | u32 tmp; | ||
711 | |||
712 | psy_cfg.of_node = dev->of_node; | ||
713 | |||
714 | if (!of_property_read_bool(dev->of_node, "maxim,pmod-enabled")) | ||
715 | pmod_enabled = true; | ||
716 | |||
717 | if (!of_property_read_u32(dev->of_node, | ||
718 | "maxim,cache-time-ms", &tmp)) | ||
719 | cache_time = tmp; | ||
720 | |||
721 | if (!of_property_read_u32(dev->of_node, | ||
722 | "rated-capacity-microamp-hours", | ||
723 | &tmp)) | ||
724 | rated_capacity = tmp / 10; /* property is in mAh */ | ||
725 | } | ||
537 | 726 | ||
538 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | 727 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; |
539 | 728 | ||
729 | sl->family_data = di; | ||
730 | |||
540 | /* enable sleep mode feature */ | 731 | /* enable sleep mode feature */ |
541 | ds2760_battery_read_status(di); | 732 | ds2760_battery_read_status(di); |
542 | status = di->raw[DS2760_STATUS_REG]; | 733 | status = di->raw[DS2760_STATUS_REG]; |
@@ -547,7 +738,7 @@ static int ds2760_battery_probe(struct platform_device *pdev) | |||
547 | 738 | ||
548 | ds2760_battery_write_status(di, status); | 739 | ds2760_battery_write_status(di, status); |
549 | 740 | ||
550 | /* set rated capacity from module param */ | 741 | /* set rated capacity from module param or device tree */ |
551 | if (rated_capacity) | 742 | if (rated_capacity) |
552 | ds2760_battery_write_rated_capacity(di, rated_capacity); | 743 | ds2760_battery_write_rated_capacity(di, rated_capacity); |
553 | 744 | ||
@@ -556,7 +747,7 @@ static int ds2760_battery_probe(struct platform_device *pdev) | |||
556 | if (current_accum) | 747 | if (current_accum) |
557 | ds2760_battery_set_current_accum(di, current_accum); | 748 | ds2760_battery_set_current_accum(di, current_accum); |
558 | 749 | ||
559 | di->bat = power_supply_register(&pdev->dev, &di->bat_desc, &psy_cfg); | 750 | di->bat = power_supply_register(dev, &di->bat_desc, &psy_cfg); |
560 | if (IS_ERR(di->bat)) { | 751 | if (IS_ERR(di->bat)) { |
561 | dev_err(di->dev, "failed to register battery\n"); | 752 | dev_err(di->dev, "failed to register battery\n"); |
562 | retval = PTR_ERR(di->bat); | 753 | retval = PTR_ERR(di->bat); |
@@ -566,14 +757,16 @@ static int ds2760_battery_probe(struct platform_device *pdev) | |||
566 | INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); | 757 | INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); |
567 | INIT_DELAYED_WORK(&di->set_charged_work, | 758 | INIT_DELAYED_WORK(&di->set_charged_work, |
568 | ds2760_battery_set_charged_work); | 759 | ds2760_battery_set_charged_work); |
569 | di->monitor_wqueue = alloc_ordered_workqueue(dev_name(&pdev->dev), | 760 | di->monitor_wqueue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); |
570 | WQ_MEM_RECLAIM); | ||
571 | if (!di->monitor_wqueue) { | 761 | if (!di->monitor_wqueue) { |
572 | retval = -ESRCH; | 762 | retval = -ESRCH; |
573 | goto workqueue_failed; | 763 | goto workqueue_failed; |
574 | } | 764 | } |
575 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); | 765 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); |
576 | 766 | ||
767 | di->pm_notifier.notifier_call = ds2760_pm_notifier; | ||
768 | register_pm_notifier(&di->pm_notifier); | ||
769 | |||
577 | goto success; | 770 | goto success; |
578 | 771 | ||
579 | workqueue_failed: | 772 | workqueue_failed: |
@@ -584,65 +777,40 @@ success: | |||
584 | return retval; | 777 | return retval; |
585 | } | 778 | } |
586 | 779 | ||
587 | static int ds2760_battery_remove(struct platform_device *pdev) | 780 | static void w1_ds2760_remove_slave(struct w1_slave *sl) |
588 | { | 781 | { |
589 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | 782 | struct ds2760_device_info *di = sl->family_data; |
590 | 783 | ||
784 | unregister_pm_notifier(&di->pm_notifier); | ||
591 | cancel_delayed_work_sync(&di->monitor_work); | 785 | cancel_delayed_work_sync(&di->monitor_work); |
592 | cancel_delayed_work_sync(&di->set_charged_work); | 786 | cancel_delayed_work_sync(&di->set_charged_work); |
593 | destroy_workqueue(di->monitor_wqueue); | 787 | destroy_workqueue(di->monitor_wqueue); |
594 | power_supply_unregister(di->bat); | 788 | power_supply_unregister(di->bat); |
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | #ifdef CONFIG_PM | ||
600 | |||
601 | static int ds2760_battery_suspend(struct platform_device *pdev, | ||
602 | pm_message_t state) | ||
603 | { | ||
604 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | ||
605 | |||
606 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static int ds2760_battery_resume(struct platform_device *pdev) | ||
612 | { | ||
613 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | ||
614 | |||
615 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
616 | power_supply_changed(di->bat); | ||
617 | |||
618 | mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); | ||
619 | |||
620 | return 0; | ||
621 | } | 789 | } |
622 | 790 | ||
623 | #else | 791 | #ifdef CONFIG_OF |
624 | 792 | static const struct of_device_id w1_ds2760_of_ids[] = { | |
625 | #define ds2760_battery_suspend NULL | 793 | { .compatible = "maxim,ds2760" }, |
626 | #define ds2760_battery_resume NULL | 794 | {} |
627 | 795 | }; | |
628 | #endif /* CONFIG_PM */ | 796 | #endif |
629 | |||
630 | MODULE_ALIAS("platform:ds2760-battery"); | ||
631 | 797 | ||
632 | static struct platform_driver ds2760_battery_driver = { | 798 | static struct w1_family_ops w1_ds2760_fops = { |
633 | .driver = { | 799 | .add_slave = w1_ds2760_add_slave, |
634 | .name = "ds2760-battery", | 800 | .remove_slave = w1_ds2760_remove_slave, |
635 | }, | 801 | .groups = w1_ds2760_groups, |
636 | .probe = ds2760_battery_probe, | ||
637 | .remove = ds2760_battery_remove, | ||
638 | .suspend = ds2760_battery_suspend, | ||
639 | .resume = ds2760_battery_resume, | ||
640 | }; | 802 | }; |
641 | 803 | ||
642 | module_platform_driver(ds2760_battery_driver); | 804 | static struct w1_family w1_ds2760_family = { |
805 | .fid = W1_FAMILY_DS2760, | ||
806 | .fops = &w1_ds2760_fops, | ||
807 | .of_match_table = of_match_ptr(w1_ds2760_of_ids), | ||
808 | }; | ||
809 | module_w1_family(w1_ds2760_family); | ||
643 | 810 | ||
644 | MODULE_LICENSE("GPL"); | ||
645 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " | 811 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " |
646 | "Matt Reimer <mreimer@vpop.net>, " | 812 | "Matt Reimer <mreimer@vpop.net>, " |
647 | "Anton Vorontsov <cbou@mail.ru>"); | 813 | "Anton Vorontsov <cbou@mail.ru>"); |
648 | MODULE_DESCRIPTION("ds2760 battery driver"); | 814 | MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); |
815 | MODULE_LICENSE("GPL"); | ||
816 | MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2760)); | ||
diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 28dc056eaafa..bc462d1ec963 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c | |||
@@ -241,10 +241,10 @@ static int gab_probe(struct platform_device *pdev) | |||
241 | struct power_supply_desc *psy_desc; | 241 | struct power_supply_desc *psy_desc; |
242 | struct power_supply_config psy_cfg = {}; | 242 | struct power_supply_config psy_cfg = {}; |
243 | struct gab_platform_data *pdata = pdev->dev.platform_data; | 243 | struct gab_platform_data *pdata = pdev->dev.platform_data; |
244 | enum power_supply_property *properties; | ||
245 | int ret = 0; | 244 | int ret = 0; |
246 | int chan; | 245 | int chan; |
247 | int index = 0; | 246 | int index = ARRAY_SIZE(gab_props); |
247 | bool any = false; | ||
248 | 248 | ||
249 | adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); | 249 | adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); |
250 | if (!adc_bat) { | 250 | if (!adc_bat) { |
@@ -278,8 +278,6 @@ static int gab_probe(struct platform_device *pdev) | |||
278 | } | 278 | } |
279 | 279 | ||
280 | memcpy(psy_desc->properties, gab_props, sizeof(gab_props)); | 280 | memcpy(psy_desc->properties, gab_props, sizeof(gab_props)); |
281 | properties = (enum power_supply_property *) | ||
282 | ((char *)psy_desc->properties + sizeof(gab_props)); | ||
283 | 281 | ||
284 | /* | 282 | /* |
285 | * getting channel from iio and copying the battery properties | 283 | * getting channel from iio and copying the battery properties |
@@ -293,15 +291,22 @@ static int gab_probe(struct platform_device *pdev) | |||
293 | adc_bat->channel[chan] = NULL; | 291 | adc_bat->channel[chan] = NULL; |
294 | } else { | 292 | } else { |
295 | /* copying properties for supported channels only */ | 293 | /* copying properties for supported channels only */ |
296 | memcpy(properties + sizeof(*(psy_desc->properties)) * index, | 294 | int index2; |
297 | &gab_dyn_props[chan], | 295 | |
298 | sizeof(gab_dyn_props[chan])); | 296 | for (index2 = 0; index2 < index; index2++) { |
299 | index++; | 297 | if (psy_desc->properties[index2] == |
298 | gab_dyn_props[chan]) | ||
299 | break; /* already known */ | ||
300 | } | ||
301 | if (index2 == index) /* really new */ | ||
302 | psy_desc->properties[index++] = | ||
303 | gab_dyn_props[chan]; | ||
304 | any = true; | ||
300 | } | 305 | } |
301 | } | 306 | } |
302 | 307 | ||
303 | /* none of the channels are supported so let's bail out */ | 308 | /* none of the channels are supported so let's bail out */ |
304 | if (index == 0) { | 309 | if (!any) { |
305 | ret = -ENODEV; | 310 | ret = -ENODEV; |
306 | goto second_mem_fail; | 311 | goto second_mem_fail; |
307 | } | 312 | } |
@@ -312,7 +317,7 @@ static int gab_probe(struct platform_device *pdev) | |||
312 | * as come channels may be not be supported by the device.So | 317 | * as come channels may be not be supported by the device.So |
313 | * we need to take care of that. | 318 | * we need to take care of that. |
314 | */ | 319 | */ |
315 | psy_desc->num_properties = ARRAY_SIZE(gab_props) + index; | 320 | psy_desc->num_properties = index; |
316 | 321 | ||
317 | adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); | 322 | adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); |
318 | if (IS_ERR(adc_bat->psy)) { | 323 | if (IS_ERR(adc_bat->psy)) { |
diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c index 7b993d669f7f..1ae3710909b7 100644 --- a/drivers/power/supply/lego_ev3_battery.c +++ b/drivers/power/supply/lego_ev3_battery.c | |||
@@ -39,7 +39,7 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, | |||
39 | union power_supply_propval *val) | 39 | union power_supply_propval *val) |
40 | { | 40 | { |
41 | struct lego_ev3_battery *batt = power_supply_get_drvdata(psy); | 41 | struct lego_ev3_battery *batt = power_supply_get_drvdata(psy); |
42 | int val2; | 42 | int ret, val2; |
43 | 43 | ||
44 | switch (psp) { | 44 | switch (psp) { |
45 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 45 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
@@ -47,11 +47,18 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, | |||
47 | break; | 47 | break; |
48 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 48 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
49 | /* battery voltage is iio channel * 2 + Vce of transistor */ | 49 | /* battery voltage is iio channel * 2 + Vce of transistor */ |
50 | iio_read_channel_processed(batt->iio_v, &val->intval); | 50 | ret = iio_read_channel_processed(batt->iio_v, &val->intval); |
51 | if (ret) | ||
52 | return ret; | ||
53 | |||
51 | val->intval *= 2000; | 54 | val->intval *= 2000; |
52 | val->intval += 200000; | 55 | val->intval += 50000; |
56 | |||
53 | /* plus adjust for shunt resistor drop */ | 57 | /* plus adjust for shunt resistor drop */ |
54 | iio_read_channel_processed(batt->iio_i, &val2); | 58 | ret = iio_read_channel_processed(batt->iio_i, &val2); |
59 | if (ret) | ||
60 | return ret; | ||
61 | |||
55 | val2 *= 1000; | 62 | val2 *= 1000; |
56 | val2 /= 15; | 63 | val2 /= 15; |
57 | val->intval += val2; | 64 | val->intval += val2; |
@@ -64,7 +71,10 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, | |||
64 | break; | 71 | break; |
65 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 72 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
66 | /* battery current is iio channel / 15 / 0.05 ohms */ | 73 | /* battery current is iio channel / 15 / 0.05 ohms */ |
67 | iio_read_channel_processed(batt->iio_i, &val->intval); | 74 | ret = iio_read_channel_processed(batt->iio_i, &val->intval); |
75 | if (ret) | ||
76 | return ret; | ||
77 | |||
68 | val->intval *= 20000; | 78 | val->intval *= 20000; |
69 | val->intval /= 15; | 79 | val->intval /= 15; |
70 | break; | 80 | break; |
diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c index 9ee601a03d9b..9ca895b0dabb 100644 --- a/drivers/power/supply/max1721x_battery.c +++ b/drivers/power/supply/max1721x_battery.c | |||
@@ -372,7 +372,7 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl) | |||
372 | } | 372 | } |
373 | 373 | ||
374 | if (!info->rsense) { | 374 | if (!info->rsense) { |
375 | dev_warn(info->w1_dev, "RSenese not calibrated, set 10 mOhms!\n"); | 375 | dev_warn(info->w1_dev, "RSense not calibrated, set 10 mOhms!\n"); |
376 | info->rsense = 1000; /* in regs in 10^-5 */ | 376 | info->rsense = 1000; /* in regs in 10^-5 */ |
377 | } | 377 | } |
378 | dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100); | 378 | dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100); |
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 6c78884bad5e..749c7926e3c9 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c | |||
@@ -567,6 +567,7 @@ static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg | |||
567 | case 4800000: | 567 | case 4800000: |
568 | case 4900000: | 568 | case 4900000: |
569 | data = (uvolt - 4700000) / 100000; | 569 | data = (uvolt - 4700000) / 100000; |
570 | break; | ||
570 | default: | 571 | default: |
571 | dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n"); | 572 | dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n"); |
572 | return -EINVAL; | 573 | return -EINVAL; |
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index d21f478741c1..e85361878450 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
18 | #include <linux/notifier.h> | 19 | #include <linux/notifier.h> |
19 | #include <linux/err.h> | 20 | #include <linux/err.h> |
@@ -140,8 +141,13 @@ static void power_supply_deferred_register_work(struct work_struct *work) | |||
140 | struct power_supply *psy = container_of(work, struct power_supply, | 141 | struct power_supply *psy = container_of(work, struct power_supply, |
141 | deferred_register_work.work); | 142 | deferred_register_work.work); |
142 | 143 | ||
143 | if (psy->dev.parent) | 144 | if (psy->dev.parent) { |
144 | mutex_lock(&psy->dev.parent->mutex); | 145 | while (!mutex_trylock(&psy->dev.parent->mutex)) { |
146 | if (psy->removing) | ||
147 | return; | ||
148 | msleep(10); | ||
149 | } | ||
150 | } | ||
145 | 151 | ||
146 | power_supply_changed(psy); | 152 | power_supply_changed(psy); |
147 | 153 | ||
@@ -1082,6 +1088,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); | |||
1082 | void power_supply_unregister(struct power_supply *psy) | 1088 | void power_supply_unregister(struct power_supply *psy) |
1083 | { | 1089 | { |
1084 | WARN_ON(atomic_dec_return(&psy->use_cnt)); | 1090 | WARN_ON(atomic_dec_return(&psy->use_cnt)); |
1091 | psy->removing = true; | ||
1085 | cancel_work_sync(&psy->changed_work); | 1092 | cancel_work_sync(&psy->changed_work); |
1086 | cancel_delayed_work_sync(&psy->deferred_register_work); | 1093 | cancel_delayed_work_sync(&psy->deferred_register_work); |
1087 | sysfs_remove_link(&psy->dev.kobj, "powers"); | 1094 | sysfs_remove_link(&psy->dev.kobj, "powers"); |
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 83d7b4115857..8ba6abf584de 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <linux/of_device.h> | ||
26 | #include <linux/power/sbs-battery.h> | 27 | #include <linux/power/sbs-battery.h> |
27 | #include <linux/power_supply.h> | 28 | #include <linux/power_supply.h> |
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -156,6 +157,9 @@ static enum power_supply_property sbs_properties[] = { | |||
156 | POWER_SUPPLY_PROP_MODEL_NAME | 157 | POWER_SUPPLY_PROP_MODEL_NAME |
157 | }; | 158 | }; |
158 | 159 | ||
160 | /* Supports special manufacturer commands from TI BQ20Z75 IC. */ | ||
161 | #define SBS_FLAGS_TI_BQ20Z75 BIT(0) | ||
162 | |||
159 | struct sbs_info { | 163 | struct sbs_info { |
160 | struct i2c_client *client; | 164 | struct i2c_client *client; |
161 | struct power_supply *power_supply; | 165 | struct power_supply *power_supply; |
@@ -168,6 +172,7 @@ struct sbs_info { | |||
168 | u32 poll_retry_count; | 172 | u32 poll_retry_count; |
169 | struct delayed_work work; | 173 | struct delayed_work work; |
170 | struct mutex mode_lock; | 174 | struct mutex mode_lock; |
175 | u32 flags; | ||
171 | }; | 176 | }; |
172 | 177 | ||
173 | static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; | 178 | static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; |
@@ -316,16 +321,40 @@ static int sbs_get_battery_presence_and_health( | |||
316 | struct i2c_client *client, enum power_supply_property psp, | 321 | struct i2c_client *client, enum power_supply_property psp, |
317 | union power_supply_propval *val) | 322 | union power_supply_propval *val) |
318 | { | 323 | { |
324 | int ret; | ||
325 | |||
326 | if (psp == POWER_SUPPLY_PROP_PRESENT) { | ||
327 | /* Dummy command; if it succeeds, battery is present. */ | ||
328 | ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr); | ||
329 | if (ret < 0) | ||
330 | val->intval = 0; /* battery disconnected */ | ||
331 | else | ||
332 | val->intval = 1; /* battery present */ | ||
333 | } else { /* POWER_SUPPLY_PROP_HEALTH */ | ||
334 | /* SBS spec doesn't have a general health command. */ | ||
335 | val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int sbs_get_ti_battery_presence_and_health( | ||
342 | struct i2c_client *client, enum power_supply_property psp, | ||
343 | union power_supply_propval *val) | ||
344 | { | ||
319 | s32 ret; | 345 | s32 ret; |
320 | 346 | ||
321 | /* | 347 | /* |
322 | * Write to ManufacturerAccess with ManufacturerAccess command | 348 | * Write to ManufacturerAccess with ManufacturerAccess command |
323 | * and then read the status. Do not check for error on the write | 349 | * and then read the status. |
324 | * since not all batteries implement write access to this command, | ||
325 | * while others mandate it. | ||
326 | */ | 350 | */ |
327 | sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, | 351 | ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, |
328 | MANUFACTURER_ACCESS_STATUS); | 352 | MANUFACTURER_ACCESS_STATUS); |
353 | if (ret < 0) { | ||
354 | if (psp == POWER_SUPPLY_PROP_PRESENT) | ||
355 | val->intval = 0; /* battery removed */ | ||
356 | return ret; | ||
357 | } | ||
329 | 358 | ||
330 | ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr); | 359 | ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr); |
331 | if (ret < 0) { | 360 | if (ret < 0) { |
@@ -600,7 +629,12 @@ static int sbs_get_property(struct power_supply *psy, | |||
600 | switch (psp) { | 629 | switch (psp) { |
601 | case POWER_SUPPLY_PROP_PRESENT: | 630 | case POWER_SUPPLY_PROP_PRESENT: |
602 | case POWER_SUPPLY_PROP_HEALTH: | 631 | case POWER_SUPPLY_PROP_HEALTH: |
603 | ret = sbs_get_battery_presence_and_health(client, psp, val); | 632 | if (client->flags & SBS_FLAGS_TI_BQ20Z75) |
633 | ret = sbs_get_ti_battery_presence_and_health(client, | ||
634 | psp, val); | ||
635 | else | ||
636 | ret = sbs_get_battery_presence_and_health(client, psp, | ||
637 | val); | ||
604 | if (psp == POWER_SUPPLY_PROP_PRESENT) | 638 | if (psp == POWER_SUPPLY_PROP_PRESENT) |
605 | return 0; | 639 | return 0; |
606 | break; | 640 | break; |
@@ -806,6 +840,7 @@ static int sbs_probe(struct i2c_client *client, | |||
806 | if (!chip) | 840 | if (!chip) |
807 | return -ENOMEM; | 841 | return -ENOMEM; |
808 | 842 | ||
843 | chip->flags = (u32)(uintptr_t)of_device_get_match_data(&client->dev); | ||
809 | chip->client = client; | 844 | chip->client = client; |
810 | chip->enable_detection = false; | 845 | chip->enable_detection = false; |
811 | psy_cfg.of_node = client->dev.of_node; | 846 | psy_cfg.of_node = client->dev.of_node; |
@@ -911,16 +946,19 @@ static int sbs_suspend(struct device *dev) | |||
911 | { | 946 | { |
912 | struct i2c_client *client = to_i2c_client(dev); | 947 | struct i2c_client *client = to_i2c_client(dev); |
913 | struct sbs_info *chip = i2c_get_clientdata(client); | 948 | struct sbs_info *chip = i2c_get_clientdata(client); |
949 | int ret; | ||
914 | 950 | ||
915 | if (chip->poll_time > 0) | 951 | if (chip->poll_time > 0) |
916 | cancel_delayed_work_sync(&chip->work); | 952 | cancel_delayed_work_sync(&chip->work); |
917 | 953 | ||
918 | /* | 954 | if (chip->flags & SBS_FLAGS_TI_BQ20Z75) { |
919 | * Write to manufacturer access with sleep command. | 955 | /* Write to manufacturer access with sleep command. */ |
920 | * Support is manufacturer dependend, so ignore errors. | 956 | ret = sbs_write_word_data(client, |
921 | */ | 957 | sbs_data[REG_MANUFACTURER_DATA].addr, |
922 | sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, | 958 | MANUFACTURER_ACCESS_SLEEP); |
923 | MANUFACTURER_ACCESS_SLEEP); | 959 | if (chip->is_present && ret < 0) |
960 | return ret; | ||
961 | } | ||
924 | 962 | ||
925 | return 0; | 963 | return 0; |
926 | } | 964 | } |
@@ -941,7 +979,10 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); | |||
941 | 979 | ||
942 | static const struct of_device_id sbs_dt_ids[] = { | 980 | static const struct of_device_id sbs_dt_ids[] = { |
943 | { .compatible = "sbs,sbs-battery" }, | 981 | { .compatible = "sbs,sbs-battery" }, |
944 | { .compatible = "ti,bq20z75" }, | 982 | { |
983 | .compatible = "ti,bq20z75", | ||
984 | .data = (void *)SBS_FLAGS_TI_BQ20Z75, | ||
985 | }, | ||
945 | { } | 986 | { } |
946 | }; | 987 | }; |
947 | MODULE_DEVICE_TABLE(of, sbs_dt_ids); | 988 | MODULE_DEVICE_TABLE(of, sbs_dt_ids); |
diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index 1f5234098aaf..814c2b81fdfe 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c | |||
@@ -1,20 +1,8 @@ | |||
1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * Battery charger driver for TI's tps65217 | 2 | // Battery charger driver for TI's tps65217 |
3 | * | 3 | // |
4 | * Copyright (c) 2015, Collabora Ltd. | 4 | // Copyright (C) 2015 Collabora Ltd. |
5 | 5 | // Author: Enric Balletbo i Serra <enric.balletbo@collabora.com> | |
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | |||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | 6 | ||
19 | /* | 7 | /* |
20 | * Battery charger driver for TI's tps65217 | 8 | * Battery charger driver for TI's tps65217 |
diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index a2740cf57ad3..15c0ca15e2aa 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c | |||
@@ -230,7 +230,8 @@ static irqreturn_t wm8350_charger_handler(int irq, void *data) | |||
230 | case WM8350_IRQ_EXT_USB_FB: | 230 | case WM8350_IRQ_EXT_USB_FB: |
231 | case WM8350_IRQ_EXT_WALL_FB: | 231 | case WM8350_IRQ_EXT_WALL_FB: |
232 | wm8350_charger_config(wm8350, policy); | 232 | wm8350_charger_config(wm8350, policy); |
233 | case WM8350_IRQ_EXT_BAT_FB: /* Fall through */ | 233 | /* Fall through */ |
234 | case WM8350_IRQ_EXT_BAT_FB: | ||
234 | power_supply_changed(power->battery); | 235 | power_supply_changed(power->battery); |
235 | power_supply_changed(power->usb); | 236 | power_supply_changed(power->usb); |
236 | power_supply_changed(power->ac); | 237 | power_supply_changed(power->ac); |
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 7931231d8e80..e22fdeddada1 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -100,18 +100,6 @@ config W1_SLAVE_DS2438 | |||
100 | Say Y here if you want to use a 1-wire | 100 | Say Y here if you want to use a 1-wire |
101 | DS2438 Smart Battery Monitor device support | 101 | DS2438 Smart Battery Monitor device support |
102 | 102 | ||
103 | config W1_SLAVE_DS2760 | ||
104 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" | ||
105 | help | ||
106 | If you enable this you will have the DS2760 battery monitor | ||
107 | chip support. | ||
108 | |||
109 | The battery monitor chip is used in many batteries/devices | ||
110 | as the one who is responsible for charging/discharging/monitoring | ||
111 | Li+ batteries. | ||
112 | |||
113 | If you are unsure, say N. | ||
114 | |||
115 | config W1_SLAVE_DS2780 | 103 | config W1_SLAVE_DS2780 |
116 | tristate "Dallas 2780 battery monitor chip" | 104 | tristate "Dallas 2780 battery monitor chip" |
117 | help | 105 | help |
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index d5f4f4d5b9e5..eab29f151413 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile | |||
@@ -14,7 +14,6 @@ obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o | |||
14 | obj-$(CONFIG_W1_SLAVE_DS2805) += w1_ds2805.o | 14 | obj-$(CONFIG_W1_SLAVE_DS2805) += w1_ds2805.o |
15 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 15 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
16 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o | 16 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o |
17 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | ||
18 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o | 17 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o |
19 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o | 18 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o |
20 | obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o | 19 | obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o |
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c deleted file mode 100644 index 26168abfb8b8..000000000000 --- a/drivers/w1/slaves/w1_ds2760.c +++ /dev/null | |||
@@ -1,175 +0,0 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2760 chip | ||
3 | * | ||
4 | * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
5 | * | ||
6 | * Use consistent with the GNU GPL is permitted, | ||
7 | * provided that this copyright notice is | ||
8 | * preserved in its entirety in all copies and derived works. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/idr.h> | ||
19 | #include <linux/gfp.h> | ||
20 | |||
21 | #include <linux/w1.h> | ||
22 | |||
23 | #include "w1_ds2760.h" | ||
24 | |||
25 | #define W1_FAMILY_DS2760 0x30 | ||
26 | |||
27 | static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, | ||
28 | int io) | ||
29 | { | ||
30 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
31 | |||
32 | if (!dev) | ||
33 | return 0; | ||
34 | |||
35 | mutex_lock(&sl->master->bus_mutex); | ||
36 | |||
37 | if (addr > DS2760_DATA_SIZE || addr < 0) { | ||
38 | count = 0; | ||
39 | goto out; | ||
40 | } | ||
41 | if (addr + count > DS2760_DATA_SIZE) | ||
42 | count = DS2760_DATA_SIZE - addr; | ||
43 | |||
44 | if (!w1_reset_select_slave(sl)) { | ||
45 | if (!io) { | ||
46 | w1_write_8(sl->master, W1_DS2760_READ_DATA); | ||
47 | w1_write_8(sl->master, addr); | ||
48 | count = w1_read_block(sl->master, buf, count); | ||
49 | } else { | ||
50 | w1_write_8(sl->master, W1_DS2760_WRITE_DATA); | ||
51 | w1_write_8(sl->master, addr); | ||
52 | w1_write_block(sl->master, buf, count); | ||
53 | /* XXX w1_write_block returns void, not n_written */ | ||
54 | } | ||
55 | } | ||
56 | |||
57 | out: | ||
58 | mutex_unlock(&sl->master->bus_mutex); | ||
59 | |||
60 | return count; | ||
61 | } | ||
62 | |||
63 | int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count) | ||
64 | { | ||
65 | return w1_ds2760_io(dev, buf, addr, count, 0); | ||
66 | } | ||
67 | EXPORT_SYMBOL(w1_ds2760_read); | ||
68 | |||
69 | int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count) | ||
70 | { | ||
71 | return w1_ds2760_io(dev, buf, addr, count, 1); | ||
72 | } | ||
73 | EXPORT_SYMBOL(w1_ds2760_write); | ||
74 | |||
75 | static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd) | ||
76 | { | ||
77 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
78 | |||
79 | if (!dev) | ||
80 | return -EINVAL; | ||
81 | |||
82 | mutex_lock(&sl->master->bus_mutex); | ||
83 | |||
84 | if (w1_reset_select_slave(sl) == 0) { | ||
85 | w1_write_8(sl->master, cmd); | ||
86 | w1_write_8(sl->master, addr); | ||
87 | } | ||
88 | |||
89 | mutex_unlock(&sl->master->bus_mutex); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | int w1_ds2760_store_eeprom(struct device *dev, int addr) | ||
94 | { | ||
95 | return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA); | ||
96 | } | ||
97 | EXPORT_SYMBOL(w1_ds2760_store_eeprom); | ||
98 | |||
99 | int w1_ds2760_recall_eeprom(struct device *dev, int addr) | ||
100 | { | ||
101 | return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA); | ||
102 | } | ||
103 | EXPORT_SYMBOL(w1_ds2760_recall_eeprom); | ||
104 | |||
105 | static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, | ||
106 | struct bin_attribute *bin_attr, char *buf, | ||
107 | loff_t off, size_t count) | ||
108 | { | ||
109 | struct device *dev = container_of(kobj, struct device, kobj); | ||
110 | return w1_ds2760_read(dev, buf, off, count); | ||
111 | } | ||
112 | |||
113 | static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE); | ||
114 | |||
115 | static struct bin_attribute *w1_ds2760_bin_attrs[] = { | ||
116 | &bin_attr_w1_slave, | ||
117 | NULL, | ||
118 | }; | ||
119 | |||
120 | static const struct attribute_group w1_ds2760_group = { | ||
121 | .bin_attrs = w1_ds2760_bin_attrs, | ||
122 | }; | ||
123 | |||
124 | static const struct attribute_group *w1_ds2760_groups[] = { | ||
125 | &w1_ds2760_group, | ||
126 | NULL, | ||
127 | }; | ||
128 | |||
129 | static int w1_ds2760_add_slave(struct w1_slave *sl) | ||
130 | { | ||
131 | int ret; | ||
132 | struct platform_device *pdev; | ||
133 | |||
134 | pdev = platform_device_alloc("ds2760-battery", PLATFORM_DEVID_AUTO); | ||
135 | if (!pdev) | ||
136 | return -ENOMEM; | ||
137 | pdev->dev.parent = &sl->dev; | ||
138 | |||
139 | ret = platform_device_add(pdev); | ||
140 | if (ret) | ||
141 | goto pdev_add_failed; | ||
142 | |||
143 | dev_set_drvdata(&sl->dev, pdev); | ||
144 | |||
145 | return 0; | ||
146 | |||
147 | pdev_add_failed: | ||
148 | platform_device_put(pdev); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static void w1_ds2760_remove_slave(struct w1_slave *sl) | ||
154 | { | ||
155 | struct platform_device *pdev = dev_get_drvdata(&sl->dev); | ||
156 | |||
157 | platform_device_unregister(pdev); | ||
158 | } | ||
159 | |||
160 | static struct w1_family_ops w1_ds2760_fops = { | ||
161 | .add_slave = w1_ds2760_add_slave, | ||
162 | .remove_slave = w1_ds2760_remove_slave, | ||
163 | .groups = w1_ds2760_groups, | ||
164 | }; | ||
165 | |||
166 | static struct w1_family w1_ds2760_family = { | ||
167 | .fid = W1_FAMILY_DS2760, | ||
168 | .fops = &w1_ds2760_fops, | ||
169 | }; | ||
170 | module_w1_family(w1_ds2760_family); | ||
171 | |||
172 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>"); | ||
173 | MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); | ||
174 | MODULE_LICENSE("GPL"); | ||
175 | MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2760)); | ||
diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h deleted file mode 100644 index 24168c94eeae..000000000000 --- a/drivers/w1/slaves/w1_ds2760.h +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2760 chip | ||
3 | * | ||
4 | * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
5 | * | ||
6 | * Use consistent with the GNU GPL is permitted, | ||
7 | * provided that this copyright notice is | ||
8 | * preserved in its entirety in all copies and derived works. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef __w1_ds2760_h__ | ||
13 | #define __w1_ds2760_h__ | ||
14 | |||
15 | /* Known commands to the DS2760 chip */ | ||
16 | #define W1_DS2760_SWAP 0xAA | ||
17 | #define W1_DS2760_READ_DATA 0x69 | ||
18 | #define W1_DS2760_WRITE_DATA 0x6C | ||
19 | #define W1_DS2760_COPY_DATA 0x48 | ||
20 | #define W1_DS2760_RECALL_DATA 0xB8 | ||
21 | #define W1_DS2760_LOCK 0x6A | ||
22 | |||
23 | /* Number of valid register addresses */ | ||
24 | #define DS2760_DATA_SIZE 0x40 | ||
25 | |||
26 | #define DS2760_PROTECTION_REG 0x00 | ||
27 | |||
28 | #define DS2760_STATUS_REG 0x01 | ||
29 | #define DS2760_STATUS_IE (1 << 2) | ||
30 | #define DS2760_STATUS_SWEN (1 << 3) | ||
31 | #define DS2760_STATUS_RNAOP (1 << 4) | ||
32 | #define DS2760_STATUS_PMOD (1 << 5) | ||
33 | |||
34 | #define DS2760_EEPROM_REG 0x07 | ||
35 | #define DS2760_SPECIAL_FEATURE_REG 0x08 | ||
36 | #define DS2760_VOLTAGE_MSB 0x0c | ||
37 | #define DS2760_VOLTAGE_LSB 0x0d | ||
38 | #define DS2760_CURRENT_MSB 0x0e | ||
39 | #define DS2760_CURRENT_LSB 0x0f | ||
40 | #define DS2760_CURRENT_ACCUM_MSB 0x10 | ||
41 | #define DS2760_CURRENT_ACCUM_LSB 0x11 | ||
42 | #define DS2760_TEMP_MSB 0x18 | ||
43 | #define DS2760_TEMP_LSB 0x19 | ||
44 | #define DS2760_EEPROM_BLOCK0 0x20 | ||
45 | #define DS2760_ACTIVE_FULL 0x20 | ||
46 | #define DS2760_EEPROM_BLOCK1 0x30 | ||
47 | #define DS2760_STATUS_WRITE_REG 0x31 | ||
48 | #define DS2760_RATED_CAPACITY 0x32 | ||
49 | #define DS2760_CURRENT_OFFSET_BIAS 0x33 | ||
50 | #define DS2760_ACTIVE_EMPTY 0x3b | ||
51 | |||
52 | extern int w1_ds2760_read(struct device *dev, char *buf, int addr, | ||
53 | size_t count); | ||
54 | extern int w1_ds2760_write(struct device *dev, char *buf, int addr, | ||
55 | size_t count); | ||
56 | extern int w1_ds2760_store_eeprom(struct device *dev, int addr); | ||
57 | extern int w1_ds2760_recall_eeprom(struct device *dev, int addr); | ||
58 | |||
59 | #endif /* !__w1_ds2760_h__ */ | ||
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index caef0e0fd817..890c038c25f8 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/kthread.h> | 26 | #include <linux/kthread.h> |
27 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
28 | #include <linux/hwmon.h> | 28 | #include <linux/hwmon.h> |
29 | #include <linux/of.h> | ||
29 | 30 | ||
30 | #include <linux/atomic.h> | 31 | #include <linux/atomic.h> |
31 | 32 | ||
@@ -686,6 +687,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
686 | sl->dev.bus = &w1_bus_type; | 687 | sl->dev.bus = &w1_bus_type; |
687 | sl->dev.release = &w1_slave_release; | 688 | sl->dev.release = &w1_slave_release; |
688 | sl->dev.groups = w1_slave_groups; | 689 | sl->dev.groups = w1_slave_groups; |
690 | sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node, | ||
691 | sl->family->of_match_table); | ||
689 | 692 | ||
690 | dev_set_name(&sl->dev, "%02x-%012llx", | 693 | dev_set_name(&sl->dev, "%02x-%012llx", |
691 | (unsigned int) sl->reg_num.family, | 694 | (unsigned int) sl->reg_num.family, |