Commit c6e8c51f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:
 "Battery/charger driver changes:

   - convert charger-manager binding to YAML

   - drop bd70528-charger driver

   - drop pm2301-charger driver

   - introduce rt5033-battery driver

   - misc improvements and fixes"

* tag 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (42 commits)
  power: supply: ab8500: Fix an old bug
  power: supply: axp288_fuel_gauge: remove redundant continue statement
  power: supply: axp288_fuel_gauge: Make "T3 MRD" no_battery_list DMI entry more generic
  power: supply: axp288_fuel_gauge: Rename fuel_gauge_blacklist to no_battery_list
  power: supply: bq24190_charger: drop of_match_ptr() from device ID table
  drivers: power: add missing MODULE_DEVICE_TABLE in keystone-reset.c
  power: supply: ab8500: add missing MODULE_DEVICE_TABLE
  power: supply: charger-manager: add missing MODULE_DEVICE_TABLE
  power: reset: regulator-poweroff: add missing MODULE_DEVICE_TABLE
  power: supply: cpcap-charger: get the battery inserted infomation from cpcap-battery
  power: supply: cpcap-battery: invalidate config when incompatible measurements are read
  power: supply: axp20x_battery: allow disabling battery charging
  power: supply: max17040: drop unused platform data support
  power: supply: max17040: simplify POWER_SUPPLY_PROP_ONLINE
  power: supply: max17040: remove non-working POWER_SUPPLY_PROP_STATUS
  power: reset: at91-sama5d2_shdwc: Remove redundant error printing in at91_shdwc_probe()
  power: reset: gpio-poweroff: add missing MODULE_DEVICE_TABLE
  power: supply: rt5033_battery: Fix device tree enumeration
  dt-bindings: power: supply: Add DT schema for richtek,rt5033-battery
  power: supply: Drop BD70528 support
  ...
parents 9d69294b f1c74a6c
charger-manager bindings
~~~~~~~~~~~~~~~~~~~~~~~~
Required properties :
- compatible : "charger-manager"
- <>-supply : for regulator consumer, named according to cm-regulator-name
- cm-chargers : name of chargers
- cm-fuel-gauge : name of battery fuel gauge
- subnode <regulator> :
- cm-regulator-name : name of charger regulator
- subnode <cable> :
- cm-cable-name : name of charger cable - one of USB, USB-HOST,
SDP, DCP, CDP, ACA, FAST-CHARGER, SLOW-CHARGER, WPT,
PD, DOCK, JIG, or MECHANICAL
- cm-cable-extcon : name of extcon dev
(optional) - cm-cable-min : minimum current of cable
(optional) - cm-cable-max : maximum current of cable
Optional properties :
- cm-name : charger manager's name (default : "battery")
- cm-poll-mode : polling mode - 0 for disabled, 1 for always, 2 for when
external power is connected, or 3 for when charging. If not present,
then polling is disabled
- cm-poll-interval : polling interval (in ms)
- cm-battery-stat : battery status - 0 for battery always present, 1 for no
battery, 2 to check presence via fuel gauge, or 3 to check presence
via charger
- cm-fullbatt-vchkdrop-volt : voltage drop (in uV) before restarting charging
- cm-fullbatt-voltage : voltage (in uV) of full battery
- cm-fullbatt-soc : state of charge to consider as full battery
- cm-fullbatt-capacity : capcity (in uAh) to consider as full battery
- cm-thermal-zone : name of external thermometer's thermal zone
- cm-battery-* : threshold battery temperature for charging
-cold : critical cold temperature of battery for charging
-cold-in-minus : flag that cold temperature is in minus degrees
-hot : critical hot temperature of battery for charging
-temp-diff : temperature difference to allow recharging
- cm-dis/charging-max = limits of charging duration
Deprecated properties:
- cm-num-chargers
- cm-fullbatt-vchkdrop-ms
Example :
charger-manager@0 {
compatible = "charger-manager";
chg-reg-supply = <&charger_regulator>;
cm-name = "battery";
/* Always polling ON : 30s */
cm-poll-mode = <1>;
cm-poll-interval = <30000>;
cm-fullbatt-vchkdrop-volt = <150000>;
cm-fullbatt-soc = <100>;
cm-battery-stat = <3>;
cm-chargers = "charger0", "charger1", "charger2";
cm-fuel-gauge = "fuelgauge0";
cm-thermal-zone = "thermal_zone.1"
/* in deci centigrade */
cm-battery-cold = <50>;
cm-battery-cold-in-minus;
cm-battery-hot = <800>;
cm-battery-temp-diff = <100>;
/* Allow charging for 5hr */
cm-charging-max = <18000000>;
/* Allow discharging for 2hr */
cm-discharging-max = <7200000>;
regulator@0 {
cm-regulator-name = "chg-reg";
cable@0 {
cm-cable-name = "USB";
cm-cable-extcon = "extcon-dev.0";
cm-cable-min = <475000>;
cm-cable-max = <500000>;
};
cable@1 {
cm-cable-name = "SDP";
cm-cable-extcon = "extcon-dev.0";
cm-cable-min = <650000>;
cm-cable-max = <675000>;
};
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/supply/charger-manager.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Charger Manager
maintainers:
- Sebastian Reichel <sre@kernel.org>
description: |
Binding for the legacy charger manager driver.
Please do not use for new products.
properties:
compatible:
const: charger-manager
cm-chargers:
description: name of chargers
$ref: /schemas/types.yaml#/definitions/string-array
cm-num-chargers:
$ref: /schemas/types.yaml#/definitions/uint32
deprecated: true
cm-fuel-gauge:
description: name of battery fuel gauge
$ref: /schemas/types.yaml#/definitions/string
cm-name:
description: name of the charger manager
default: battery
$ref: /schemas/types.yaml#/definitions/string
cm-poll-mode:
description: polling mode
default: 0
enum:
- 0 # disabled
- 1 # always
- 2 # when external power is connected
- 3 # when charging
cm-poll-interval:
description: polling interval (in ms)
$ref: /schemas/types.yaml#/definitions/uint32
cm-battery-stat:
description: battery status
enum:
- 0 # battery always present
- 1 # no battery
- 2 # check presence via fuel gauge
- 3 # check presence via charger
cm-fullbatt-vchkdrop-volt:
description: voltage drop before restarting charging in uV
$ref: /schemas/types.yaml#/definitions/uint32
cm-fullbatt-vchkdrop-ms:
deprecated: true
cm-fullbatt-voltage:
description: voltage of full battery in uV
$ref: /schemas/types.yaml#/definitions/uint32
cm-fullbatt-soc:
description: state of charge to consider as full battery in %
$ref: /schemas/types.yaml#/definitions/uint32
cm-fullbatt-capacity:
description: capcity to consider as full battery in uAh
$ref: /schemas/types.yaml#/definitions/uint32
cm-thermal-zone:
description: name of external thermometer's thermal zone
$ref: /schemas/types.yaml#/definitions/string
cm-discharging-max:
description: limits of discharging duration in ms
$ref: /schemas/types.yaml#/definitions/uint32
cm-charging-max:
description: limits of charging duration in ms
$ref: /schemas/types.yaml#/definitions/uint32
cm-battery-cold:
description: critical cold temperature of battery for charging in deci-degree celsius
$ref: /schemas/types.yaml#/definitions/uint32
cm-battery-cold-in-minus:
description: if set cm-battery-cold temperature is in minus degrees
type: boolean
cm-battery-hot:
description: critical hot temperature of battery for charging in deci-degree celsius
$ref: /schemas/types.yaml#/definitions/uint32
cm-battery-temp-diff:
description: temperature difference to allow recharging in deci-degree celsius
$ref: /schemas/types.yaml#/definitions/uint32
patternProperties:
"-supply$":
description: regulator consumer, named according to cm-regulator-name
$ref: /schemas/types.yaml#/definitions/phandle
"^regulator[@-][0-9]$":
type: object
properties:
cm-regulator-name:
description: name of charger regulator
$ref: /schemas/types.yaml#/definitions/string
required:
- cm-regulator-name
additionalProperties: false
patternProperties:
"^cable[@-][0-9]$":
type: object
properties:
cm-cable-name:
description: name of charger cable
enum:
- USB
- USB-HOST
- SDP
- DCP
- CDP
- ACA
- FAST-CHARGER
- SLOW-CHARGER
- WPT
- PD
- DOCK
- JIG
- MECHANICAL
cm-cable-extcon:
description: name of extcon dev
$ref: /schemas/types.yaml#/definitions/string
cm-cable-min:
description: minimum current of cable in uA
$ref: /schemas/types.yaml#/definitions/uint32
cm-cable-max:
description: maximum current of cable in uA
$ref: /schemas/types.yaml#/definitions/uint32
required:
- cm-cable-name
- cm-cable-extcon
additionalProperties: false
required:
- compatible
- cm-chargers
- cm-fuel-gauge
additionalProperties: false
examples:
- |
charger-manager {
compatible = "charger-manager";
chg-reg-supply = <&charger_regulator>;
cm-name = "battery";
/* Always polling ON : 30s */
cm-poll-mode = <1>;
cm-poll-interval = <30000>;
cm-fullbatt-vchkdrop-volt = <150000>;
cm-fullbatt-soc = <100>;
cm-battery-stat = <3>;
cm-chargers = "charger0", "charger1", "charger2";
cm-fuel-gauge = "fuelgauge0";
cm-thermal-zone = "thermal_zone.1";
/* in deci centigrade */
cm-battery-cold = <50>;
cm-battery-cold-in-minus;
cm-battery-hot = <800>;
cm-battery-temp-diff = <100>;
/* Allow charging for 5hr */
cm-charging-max = <18000000>;
/* Allow discharging for 2hr */
cm-discharging-max = <7200000>;
regulator-0 {
cm-regulator-name = "chg-reg";
cable-0 {
cm-cable-name = "USB";
cm-cable-extcon = "extcon-dev.0";
cm-cable-min = <475000>;
cm-cable-max = <500000>;
};
cable-1 {
cm-cable-name = "SDP";
cm-cable-extcon = "extcon-dev.0";
cm-cable-min = <650000>;
cm-cable-max = <675000>;
};
};
};
...@@ -89,7 +89,7 @@ examples: ...@@ -89,7 +89,7 @@ examples:
reg = <0x36>; reg = <0x36>;
maxim,alert-low-soc-level = <10>; maxim,alert-low-soc-level = <10>;
interrupt-parent = <&gpio7>; interrupt-parent = <&gpio7>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
wakeup-source; wakeup-source;
}; };
}; };
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/power/supply/richtek,rt5033-battery.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Richtek RT5033 PMIC Fuel Gauge
maintainers:
- Stephan Gerhold <stephan@gerhold.net>
allOf:
- $ref: power-supply.yaml#
properties:
compatible:
const: richtek,rt5033-battery
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
battery@35 {
compatible = "richtek,rt5033-battery";
reg = <0x35>;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
battery@35 {
compatible = "richtek,rt5033-battery";
reg = <0x35>;
interrupt-parent = <&msmgpio>;
interrupts = <121 IRQ_TYPE_EDGE_FALLING>;
};
};
...@@ -14827,6 +14827,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git ...@@ -14827,6 +14827,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
F: Documentation/ABI/testing/sysfs-class-power F: Documentation/ABI/testing/sysfs-class-power
F: Documentation/devicetree/bindings/power/supply/ F: Documentation/devicetree/bindings/power/supply/
F: drivers/power/supply/ F: drivers/power/supply/
F: include/linux/power/
F: include/linux/power_supply.h F: include/linux/power_supply.h
POWERNV OPERATOR PANEL LCD DISPLAY DRIVER POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
...@@ -16213,7 +16214,7 @@ W: http://www.ibm.com/developerworks/linux/linux390/ ...@@ -16213,7 +16214,7 @@ W: http://www.ibm.com/developerworks/linux/linux390/
F: drivers/s390/scsi/zfcp_* F: drivers/s390/scsi/zfcp_*
S3C ADC BATTERY DRIVER S3C ADC BATTERY DRIVER
M: Krzysztof Kozlowski <krzk@kernel.org> M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
L: linux-samsung-soc@vger.kernel.org L: linux-samsung-soc@vger.kernel.org
S: Odd Fixes S: Odd Fixes
F: drivers/power/supply/s3c_adc_battery.c F: drivers/power/supply/s3c_adc_battery.c
......
...@@ -351,10 +351,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) ...@@ -351,10 +351,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res); at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(at91_shdwc->shdwc_base)) { if (IS_ERR(at91_shdwc->shdwc_base))
dev_err(&pdev->dev, "Could not map reset controller address\n");
return PTR_ERR(at91_shdwc->shdwc_base); return PTR_ERR(at91_shdwc->shdwc_base);
}
match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node); match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
at91_shdwc->rcfg = match->data; at91_shdwc->rcfg = match->data;
......
...@@ -90,6 +90,7 @@ static const struct of_device_id of_gpio_poweroff_match[] = { ...@@ -90,6 +90,7 @@ static const struct of_device_id of_gpio_poweroff_match[] = {
{ .compatible = "gpio-poweroff", }, { .compatible = "gpio-poweroff", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
static struct platform_driver gpio_poweroff_driver = { static struct platform_driver gpio_poweroff_driver = {
.probe = gpio_poweroff_probe, .probe = gpio_poweroff_probe,
......
...@@ -71,6 +71,7 @@ static const struct of_device_id rsctrl_of_match[] = { ...@@ -71,6 +71,7 @@ static const struct of_device_id rsctrl_of_match[] = {
{.compatible = "ti,keystone-reset", }, {.compatible = "ti,keystone-reset", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rsctrl_of_match);
static int rsctrl_probe(struct platform_device *pdev) static int rsctrl_probe(struct platform_device *pdev)
{ {
......
...@@ -64,6 +64,7 @@ static const struct of_device_id of_regulator_poweroff_match[] = { ...@@ -64,6 +64,7 @@ static const struct of_device_id of_regulator_poweroff_match[] = {
{ .compatible = "regulator-poweroff", }, { .compatible = "regulator-poweroff", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match);
static struct platform_driver regulator_poweroff_driver = { static struct platform_driver regulator_poweroff_driver = {
.probe = regulator_poweroff_probe, .probe = regulator_poweroff_probe,
......
...@@ -712,7 +712,8 @@ config BATTERY_GOLDFISH ...@@ -712,7 +712,8 @@ config BATTERY_GOLDFISH
config BATTERY_RT5033 config BATTERY_RT5033
tristate "RT5033 fuel gauge support" tristate "RT5033 fuel gauge support"
depends on MFD_RT5033 depends on I2C
select REGMAP_I2C
help help
This adds support for battery fuel gauge in Richtek RT5033 PMIC. This adds support for battery fuel gauge in Richtek RT5033 PMIC.
The fuelgauge calculates and determines the battery state of charge The fuelgauge calculates and determines the battery state of charge
...@@ -760,15 +761,6 @@ config CHARGER_UCS1002 ...@@ -760,15 +761,6 @@ config CHARGER_UCS1002
Say Y to enable support for Microchip UCS1002 Programmable Say Y to enable support for Microchip UCS1002 Programmable
USB Port Power Controller with Charger Emulation. USB Port Power Controller with Charger Emulation.
config CHARGER_BD70528
tristate "ROHM bd70528 charger driver"
depends on MFD_ROHM_BD70528
select LINEAR_RANGES
help
Say Y here to enable support for getting battery status
information and altering charger configurations from charger
block of the ROHM BD70528 Power Management IC.
config CHARGER_BD99954 config CHARGER_BD99954
tristate "ROHM bd99954 charger driver" tristate "ROHM bd99954 charger driver"
depends on I2C depends on I2C
......
...@@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o ...@@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
...@@ -96,7 +96,6 @@ obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o ...@@ -96,7 +96,6 @@ obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
......
...@@ -506,9 +506,6 @@ struct abx500_bm_data { ...@@ -506,9 +506,6 @@ struct abx500_bm_data {
int usb_safety_tmr_h; int usb_safety_tmr_h;
int bkup_bat_v; int bkup_bat_v;
int bkup_bat_i; int bkup_bat_i;
bool autopower_cfg;
bool ac_enabled;
bool usb_enabled;
bool no_maintenance; bool no_maintenance;
bool capacity_scaling; bool capacity_scaling;
bool chg_unknown_bat; bool chg_unknown_bat;
...@@ -730,4 +727,8 @@ int ab8500_bm_of_probe(struct device *dev, ...@@ -730,4 +727,8 @@ int ab8500_bm_of_probe(struct device *dev,
struct device_node *np, struct device_node *np,
struct abx500_bm_data *bm); struct abx500_bm_data *bm);
extern struct platform_driver ab8500_fg_driver;
extern struct platform_driver ab8500_btemp_driver;
extern struct platform_driver abx500_chargalg_driver;
#endif /* _AB8500_CHARGER_H_ */ #endif /* _AB8500_CHARGER_H_ */
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* - POWER_SUPPLY_TYPE_USB, * - POWER_SUPPLY_TYPE_USB,
* because only them store as drv_data pointer to struct ux500_charger. * because only them store as drv_data pointer to struct ux500_charger.
*/ */
#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy) #define psy_to_ux500_charger(x) power_supply_get_drvdata(x)
/* Forward declaration */ /* Forward declaration */
struct ux500_charger; struct ux500_charger;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/component.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev) ...@@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
return 0; return 0;
} }
static int ab8500_btemp_remove(struct platform_device *pdev)
{
struct ab8500_btemp *di = platform_get_drvdata(pdev);
int i, irq;
/* Disable interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
free_irq(irq, di);
}
/* Delete the work queue */
destroy_workqueue(di->btemp_wq);
flush_scheduled_work();
power_supply_unregister(di->btemp_psy);
return 0;
}
static char *supply_interface[] = { static char *supply_interface[] = {
"ab8500_chargalg", "ab8500_chargalg",
"ab8500_fg", "ab8500_fg",
...@@ -966,9 +947,42 @@ static const struct power_supply_desc ab8500_btemp_desc = { ...@@ -966,9 +947,42 @@ static const struct power_supply_desc ab8500_btemp_desc = {
.external_power_changed = ab8500_btemp_external_power_changed, .external_power_changed = ab8500_btemp_external_power_changed,
}; };
static int ab8500_btemp_bind(struct device *dev, struct device *master,
void *data)
{
struct ab8500_btemp *di = dev_get_drvdata(dev);
/* Create a work queue for the btemp */
di->btemp_wq =
alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
if (di->btemp_wq == NULL) {
dev_err(dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Kick off periodic temperature measurements */
ab8500_btemp_periodic(di, true);
return 0;
}
static void ab8500_btemp_unbind(struct device *dev, struct device *master,
void *data)
{
struct ab8500_btemp *di = dev_get_drvdata(dev);
/* Delete the work queue */
destroy_workqueue(di->btemp_wq);
flush_scheduled_work();
}
static const struct component_ops ab8500_btemp_component_ops = {
.bind = ab8500_btemp_bind,
.unbind = ab8500_btemp_unbind,
};
static int ab8500_btemp_probe(struct platform_device *pdev) static int ab8500_btemp_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
struct power_supply_config psy_cfg = {}; struct power_supply_config psy_cfg = {};
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ab8500_btemp *di; struct ab8500_btemp *di;
...@@ -981,12 +995,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) ...@@ -981,12 +995,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
di->bm = &ab8500_bm_data; di->bm = &ab8500_bm_data;
ret = ab8500_bm_of_probe(dev, np, di->bm);
if (ret) {
dev_err(dev, "failed to get battery information\n");
return ret;
}
/* get parent data */ /* get parent data */
di->dev = dev; di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent); di->parent = dev_get_drvdata(pdev->dev.parent);
...@@ -1011,14 +1019,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) ...@@ -1011,14 +1019,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
psy_cfg.drv_data = di; psy_cfg.drv_data = di;
/* Create a work queue for the btemp */
di->btemp_wq =
alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
if (di->btemp_wq == NULL) {
dev_err(dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Init work for measuring temperature periodically */ /* Init work for measuring temperature periodically */
INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
ab8500_btemp_periodic_work); ab8500_btemp_periodic_work);
...@@ -1031,7 +1031,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev) ...@@ -1031,7 +1031,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
AB8500_BTEMP_HIGH_TH, &val); AB8500_BTEMP_HIGH_TH, &val);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s ab8500 read failed\n", __func__); dev_err(dev, "%s ab8500 read failed\n", __func__);
goto free_btemp_wq; return ret;
} }
switch (val) { switch (val) {
case BTEMP_HIGH_TH_57_0: case BTEMP_HIGH_TH_57_0:
...@@ -1050,30 +1050,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev) ...@@ -1050,30 +1050,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
} }
/* Register BTEMP power supply class */ /* Register BTEMP power supply class */
di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc, di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc,
&psy_cfg); &psy_cfg);
if (IS_ERR(di->btemp_psy)) { if (IS_ERR(di->btemp_psy)) {
dev_err(dev, "failed to register BTEMP psy\n"); dev_err(dev, "failed to register BTEMP psy\n");
ret = PTR_ERR(di->btemp_psy); return PTR_ERR(di->btemp_psy);
goto free_btemp_wq;
} }
/* Register interrupts */ /* Register interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) { for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
if (irq < 0) { if (irq < 0)
ret = irq; return irq;
goto free_irq;
}
ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr, ret = devm_request_threaded_irq(dev, irq, NULL,
ab8500_btemp_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_btemp_irq[i].name, di); ab8500_btemp_irq[i].name, di);
if (ret) { if (ret) {
dev_err(dev, "failed to request %s IRQ %d: %d\n" dev_err(dev, "failed to request %s IRQ %d: %d\n"
, ab8500_btemp_irq[i].name, irq, ret); , ab8500_btemp_irq[i].name, irq, ret);
goto free_irq; return ret;
} }
dev_dbg(dev, "Requested %s IRQ %d: %d\n", dev_dbg(dev, "Requested %s IRQ %d: %d\n",
ab8500_btemp_irq[i].name, irq, ret); ab8500_btemp_irq[i].name, irq, ret);
...@@ -1081,23 +1079,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev) ...@@ -1081,23 +1079,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, di); platform_set_drvdata(pdev, di);
/* Kick off periodic temperature measurements */
ab8500_btemp_periodic(di, true);
list_add_tail(&di->node, &ab8500_btemp_list); list_add_tail(&di->node, &ab8500_btemp_list);
return ret; return component_add(dev, &ab8500_btemp_component_ops);
}
free_irq: static int ab8500_btemp_remove(struct platform_device *pdev)
/* We also have to free all successfully registered irqs */ {
for (i = i - 1; i >= 0; i--) { component_del(&pdev->dev, &ab8500_btemp_component_ops);
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
free_irq(irq, di);
}
power_supply_unregister(di->btemp_psy); return 0;
free_btemp_wq:
destroy_workqueue(di->btemp_wq);
return ret;
} }
static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume); static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
...@@ -1106,8 +1097,9 @@ static const struct of_device_id ab8500_btemp_match[] = { ...@@ -1106,8 +1097,9 @@ static const struct of_device_id ab8500_btemp_match[] = {
{ .compatible = "stericsson,ab8500-btemp", }, { .compatible = "stericsson,ab8500-btemp", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, ab8500_btemp_match);
static struct platform_driver ab8500_btemp_driver = { struct platform_driver ab8500_btemp_driver = {
.probe = ab8500_btemp_probe, .probe = ab8500_btemp_probe,
.remove = ab8500_btemp_remove, .remove = ab8500_btemp_remove,
.driver = { .driver = {
...@@ -1116,20 +1108,6 @@ static struct platform_driver ab8500_btemp_driver = { ...@@ -1116,20 +1108,6 @@ static struct platform_driver ab8500_btemp_driver = {
.pm = &ab8500_btemp_pm_ops, .pm = &ab8500_btemp_pm_ops,
}, },
}; };
static int __init ab8500_btemp_init(void)
{
return platform_driver_register(&ab8500_btemp_driver);
}
static void __exit ab8500_btemp_exit(void)
{
platform_driver_unregister(&ab8500_btemp_driver);
}
device_initcall(ab8500_btemp_init);
module_exit(ab8500_btemp_exit);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
MODULE_ALIAS("platform:ab8500-btemp"); MODULE_ALIAS("platform:ab8500-btemp");
......
This diff is collapsed.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/component.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -59,7 +60,7 @@ ...@@ -59,7 +60,7 @@
((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1)))); ((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1))));
/** /**
* struct ab8500_fg_interrupts - ab8500 fg interupts * struct ab8500_fg_interrupts - ab8500 fg interrupts
* @name: name of the interrupt * @name: name of the interrupt
* @isr function pointer to the isr * @isr function pointer to the isr
*/ */
...@@ -2980,27 +2981,6 @@ static int __maybe_unused ab8500_fg_suspend(struct device *dev) ...@@ -2980,27 +2981,6 @@ static int __maybe_unused ab8500_fg_suspend(struct device *dev)
return 0; return 0;
} }
static int ab8500_fg_remove(struct platform_device *pdev)
{
int ret = 0;
struct ab8500_fg *di = platform_get_drvdata(pdev);
list_del(&di->node);
/* Disable coulomb counter */
ret = ab8500_fg_coulomb_counter(di, false);
if (ret)
dev_err(di->dev, "failed to disable coulomb counter\n");
destroy_workqueue(di->fg_wq);
ab8500_fg_sysfs_exit(di);
flush_scheduled_work();
ab8500_fg_sysfs_psy_remove_attrs(di);
power_supply_unregister(di->fg_psy);
return ret;
}
/* ab8500 fg driver interrupts and their respective isr */ /* ab8500 fg driver interrupts and their respective isr */
static struct ab8500_fg_interrupts ab8500_fg_irq[] = { static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
{"NCONV_ACCU", ab8500_fg_cc_convend_handler}, {"NCONV_ACCU", ab8500_fg_cc_convend_handler},
...@@ -3024,11 +3004,50 @@ static const struct power_supply_desc ab8500_fg_desc = { ...@@ -3024,11 +3004,50 @@ static const struct power_supply_desc ab8500_fg_desc = {
.external_power_changed = ab8500_fg_external_power_changed, .external_power_changed = ab8500_fg_external_power_changed,
}; };
static int ab8500_fg_bind(struct device *dev, struct device *master,
void *data)
{
struct ab8500_fg *di = dev_get_drvdata(dev);
/* Create a work queue for running the FG algorithm */
di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
if (di->fg_wq == NULL) {
dev_err(dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Start the coulomb counter */
ab8500_fg_coulomb_counter(di, true);
/* Run the FG algorithm */
queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
return 0;
}
static void ab8500_fg_unbind(struct device *dev, struct device *master,
void *data)
{
struct ab8500_fg *di = dev_get_drvdata(dev);
int ret;
/* Disable coulomb counter */
ret = ab8500_fg_coulomb_counter(di, false);
if (ret)
dev_err(dev, "failed to disable coulomb counter\n");
destroy_workqueue(di->fg_wq);
flush_scheduled_work();
}
static const struct component_ops ab8500_fg_component_ops = {
.bind = ab8500_fg_bind,
.unbind = ab8500_fg_unbind,
};
static int ab8500_fg_probe(struct platform_device *pdev) static int ab8500_fg_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
struct power_supply_config psy_cfg = {};
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct power_supply_config psy_cfg = {};
struct ab8500_fg *di; struct ab8500_fg *di;
int i, irq; int i, irq;
int ret = 0; int ret = 0;
...@@ -3039,12 +3058,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3039,12 +3058,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
di->bm = &ab8500_bm_data; di->bm = &ab8500_bm_data;
ret = ab8500_bm_of_probe(dev, np, di->bm);
if (ret) {
dev_err(dev, "failed to get battery information\n");
return ret;
}
mutex_init(&di->cc_lock); mutex_init(&di->cc_lock);
/* get parent data */ /* get parent data */
...@@ -3074,13 +3087,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3074,13 +3087,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT); ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
/* Create a work queue for running the FG algorithm */
di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
if (di->fg_wq == NULL) {
dev_err(dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Init work for running the fg algorithm instantly */ /* Init work for running the fg algorithm instantly */
INIT_WORK(&di->fg_work, ab8500_fg_instant_work); INIT_WORK(&di->fg_work, ab8500_fg_instant_work);
...@@ -3113,7 +3119,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3113,7 +3119,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ret = ab8500_fg_init_hw_registers(di); ret = ab8500_fg_init_hw_registers(di);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize registers\n"); dev_err(dev, "failed to initialize registers\n");
goto free_inst_curr_wq; return ret;
} }
/* Consider battery unknown until we're informed otherwise */ /* Consider battery unknown until we're informed otherwise */
...@@ -3121,15 +3127,13 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3121,15 +3127,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
di->flags.batt_id_received = false; di->flags.batt_id_received = false;
/* Register FG power supply class */ /* Register FG power supply class */
di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg); di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
if (IS_ERR(di->fg_psy)) { if (IS_ERR(di->fg_psy)) {
dev_err(dev, "failed to register FG psy\n"); dev_err(dev, "failed to register FG psy\n");
ret = PTR_ERR(di->fg_psy); return PTR_ERR(di->fg_psy);
goto free_inst_curr_wq;
} }
di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer); di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
ab8500_fg_coulomb_counter(di, true);
/* /*
* Initialize completion used to notify completion and start * Initialize completion used to notify completion and start
...@@ -3141,19 +3145,18 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3141,19 +3145,18 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Register primary interrupt handlers */ /* Register primary interrupt handlers */
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) { for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
if (irq < 0) { if (irq < 0)
ret = irq; return irq;
goto free_irq;
}
ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr, ret = devm_request_threaded_irq(dev, irq, NULL,
ab8500_fg_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_fg_irq[i].name, di); ab8500_fg_irq[i].name, di);
if (ret != 0) { if (ret != 0) {
dev_err(dev, "failed to request %s IRQ %d: %d\n", dev_err(dev, "failed to request %s IRQ %d: %d\n",
ab8500_fg_irq[i].name, irq, ret); ab8500_fg_irq[i].name, irq, ret);
goto free_irq; return ret;
} }
dev_dbg(dev, "Requested %s IRQ %d: %d\n", dev_dbg(dev, "Requested %s IRQ %d: %d\n",
ab8500_fg_irq[i].name, irq, ret); ab8500_fg_irq[i].name, irq, ret);
...@@ -3168,14 +3171,14 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3168,14 +3171,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ret = ab8500_fg_sysfs_init(di); ret = ab8500_fg_sysfs_init(di);
if (ret) { if (ret) {
dev_err(dev, "failed to create sysfs entry\n"); dev_err(dev, "failed to create sysfs entry\n");
goto free_irq; return ret;
} }
ret = ab8500_fg_sysfs_psy_create_attrs(di); ret = ab8500_fg_sysfs_psy_create_attrs(di);
if (ret) { if (ret) {
dev_err(dev, "failed to create FG psy\n"); dev_err(dev, "failed to create FG psy\n");
ab8500_fg_sysfs_exit(di); ab8500_fg_sysfs_exit(di);
goto free_irq; return ret;
} }
/* Calibrate the fg first time */ /* Calibrate the fg first time */
...@@ -3185,24 +3188,21 @@ static int ab8500_fg_probe(struct platform_device *pdev) ...@@ -3185,24 +3188,21 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Use room temp as default value until we get an update from driver. */ /* Use room temp as default value until we get an update from driver. */
di->bat_temp = 210; di->bat_temp = 210;
/* Run the FG algorithm */
queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
list_add_tail(&di->node, &ab8500_fg_list); list_add_tail(&di->node, &ab8500_fg_list);
return ret; return component_add(dev, &ab8500_fg_component_ops);
}
free_irq: static int ab8500_fg_remove(struct platform_device *pdev)
/* We also have to free all registered irqs */ {
while (--i >= 0) { int ret = 0;
/* Last assignment of i from primary interrupt handlers */ struct ab8500_fg *di = platform_get_drvdata(pdev);
irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
free_irq(irq, di); component_del(&pdev->dev, &ab8500_fg_component_ops);
} list_del(&di->node);
ab8500_fg_sysfs_exit(di);
ab8500_fg_sysfs_psy_remove_attrs(di);
power_supply_unregister(di->fg_psy);
free_inst_curr_wq:
destroy_workqueue(di->fg_wq);
return ret; return ret;
} }
...@@ -3212,8 +3212,9 @@ static const struct of_device_id ab8500_fg_match[] = { ...@@ -3212,8 +3212,9 @@ static const struct of_device_id ab8500_fg_match[] = {
{ .compatible = "stericsson,ab8500-fg", }, { .compatible = "stericsson,ab8500-fg", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, ab8500_fg_match);
static struct platform_driver ab8500_fg_driver = { struct platform_driver ab8500_fg_driver = {
.probe = ab8500_fg_probe, .probe = ab8500_fg_probe,
.remove = ab8500_fg_remove, .remove = ab8500_fg_remove,
.driver = { .driver = {
...@@ -3222,20 +3223,6 @@ static struct platform_driver ab8500_fg_driver = { ...@@ -3222,20 +3223,6 @@ static struct platform_driver ab8500_fg_driver = {
.pm = &ab8500_fg_pm_ops, .pm = &ab8500_fg_pm_ops,
}, },
}; };
static int __init ab8500_fg_init(void)
{
return platform_driver_register(&ab8500_fg_driver);
}
static void __exit ab8500_fg_exit(void)
{
platform_driver_unregister(&ab8500_fg_driver);
}
subsys_initcall_sync(ab8500_fg_init);
module_exit(ab8500_fg_exit);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:ab8500-fg"); MODULE_ALIAS("platform:ab8500-fg");
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/component.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -1943,13 +1944,44 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev) ...@@ -1943,13 +1944,44 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
return 0; return 0;
} }
static int abx500_chargalg_remove(struct platform_device *pdev) static char *supply_interface[] = {
"ab8500_fg",
};
static const struct power_supply_desc abx500_chargalg_desc = {
.name = "abx500_chargalg",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = abx500_chargalg_props,
.num_properties = ARRAY_SIZE(abx500_chargalg_props),
.get_property = abx500_chargalg_get_property,
.external_power_changed = abx500_chargalg_external_power_changed,
};
static int abx500_chargalg_bind(struct device *dev, struct device *master,
void *data)
{ {
struct abx500_chargalg *di = platform_get_drvdata(pdev); struct abx500_chargalg *di = dev_get_drvdata(dev);
/* sysfs interface to enable/disbale charging from user space */ /* Create a work queue for the chargalg */
abx500_chargalg_sysfs_exit(di); di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
WQ_MEM_RECLAIM);
if (di->chargalg_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Run the charging algorithm */
queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
return 0;
}
static void abx500_chargalg_unbind(struct device *dev, struct device *master,
void *data)
{
struct abx500_chargalg *di = dev_get_drvdata(dev);
/* Stop all timers and work */
hrtimer_cancel(&di->safety_timer); hrtimer_cancel(&di->safety_timer);
hrtimer_cancel(&di->maintenance_timer); hrtimer_cancel(&di->maintenance_timer);
...@@ -1959,48 +1991,29 @@ static int abx500_chargalg_remove(struct platform_device *pdev) ...@@ -1959,48 +1991,29 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
/* Delete the work queue */ /* Delete the work queue */
destroy_workqueue(di->chargalg_wq); destroy_workqueue(di->chargalg_wq);
flush_scheduled_work();
power_supply_unregister(di->chargalg_psy);
return 0;
} }
static char *supply_interface[] = { static const struct component_ops abx500_chargalg_component_ops = {
"ab8500_fg", .bind = abx500_chargalg_bind,
}; .unbind = abx500_chargalg_unbind,
static const struct power_supply_desc abx500_chargalg_desc = {
.name = "abx500_chargalg",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = abx500_chargalg_props,
.num_properties = ARRAY_SIZE(abx500_chargalg_props),
.get_property = abx500_chargalg_get_property,
.external_power_changed = abx500_chargalg_external_power_changed,
}; };
static int abx500_chargalg_probe(struct platform_device *pdev) static int abx500_chargalg_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev;
struct power_supply_config psy_cfg = {}; struct power_supply_config psy_cfg = {};
struct abx500_chargalg *di; struct abx500_chargalg *di;
int ret = 0; int ret = 0;
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
if (!di) { if (!di)
dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
return -ENOMEM; return -ENOMEM;
}
di->bm = &ab8500_bm_data; di->bm = &ab8500_bm_data;
ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
if (ret) {
dev_err(&pdev->dev, "failed to get battery information\n");
return ret;
}
/* get device struct and parent */ /* get device struct and parent */
di->dev = &pdev->dev; di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent); di->parent = dev_get_drvdata(pdev->dev.parent);
psy_cfg.supplied_to = supply_interface; psy_cfg.supplied_to = supply_interface;
...@@ -2016,14 +2029,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev) ...@@ -2016,14 +2029,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->maintenance_timer.function = di->maintenance_timer.function =
abx500_chargalg_maintenance_timer_expired; abx500_chargalg_maintenance_timer_expired;
/* Create a work queue for the chargalg */
di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
WQ_MEM_RECLAIM);
if (di->chargalg_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
}
/* Init work for chargalg */ /* Init work for chargalg */
INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work, INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work,
abx500_chargalg_periodic_work); abx500_chargalg_periodic_work);
...@@ -2037,12 +2042,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev) ...@@ -2037,12 +2042,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->chg_info.prev_conn_chg = -1; di->chg_info.prev_conn_chg = -1;
/* Register chargalg power supply class */ /* Register chargalg power supply class */
di->chargalg_psy = power_supply_register(di->dev, &abx500_chargalg_desc, di->chargalg_psy = devm_power_supply_register(di->dev,
&abx500_chargalg_desc,
&psy_cfg); &psy_cfg);
if (IS_ERR(di->chargalg_psy)) { if (IS_ERR(di->chargalg_psy)) {
dev_err(di->dev, "failed to register chargalg psy\n"); dev_err(di->dev, "failed to register chargalg psy\n");
ret = PTR_ERR(di->chargalg_psy); return PTR_ERR(di->chargalg_psy);
goto free_chargalg_wq;
} }
platform_set_drvdata(pdev, di); platform_set_drvdata(pdev, di);
...@@ -2051,21 +2056,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev) ...@@ -2051,21 +2056,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
ret = abx500_chargalg_sysfs_init(di); ret = abx500_chargalg_sysfs_init(di);
if (ret) { if (ret) {
dev_err(di->dev, "failed to create sysfs entry\n"); dev_err(di->dev, "failed to create sysfs entry\n");
goto free_psy; return ret;
} }
di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH; di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
/* Run the charging algorithm */
queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
dev_info(di->dev, "probe success\n"); dev_info(di->dev, "probe success\n");
return ret; return component_add(dev, &abx500_chargalg_component_ops);
}
free_psy: static int abx500_chargalg_remove(struct platform_device *pdev)
power_supply_unregister(di->chargalg_psy); {
free_chargalg_wq: struct abx500_chargalg *di = platform_get_drvdata(pdev);
destroy_workqueue(di->chargalg_wq);
return ret; component_del(&pdev->dev, &abx500_chargalg_component_ops);
/* sysfs interface to enable/disable charging from user space */
abx500_chargalg_sysfs_exit(di);
return 0;
} }
static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume); static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
...@@ -2075,7 +2083,7 @@ static const struct of_device_id ab8500_chargalg_match[] = { ...@@ -2075,7 +2083,7 @@ static const struct of_device_id ab8500_chargalg_match[] = {
{ }, { },
}; };
static struct platform_driver abx500_chargalg_driver = { struct platform_driver abx500_chargalg_driver = {
.probe = abx500_chargalg_probe, .probe = abx500_chargalg_probe,
.remove = abx500_chargalg_remove, .remove = abx500_chargalg_remove,
.driver = { .driver = {
...@@ -2084,9 +2092,6 @@ static struct platform_driver abx500_chargalg_driver = { ...@@ -2084,9 +2092,6 @@ static struct platform_driver abx500_chargalg_driver = {
.pm = &abx500_chargalg_pm_ops, .pm = &abx500_chargalg_pm_ops,
}, },
}; };
module_platform_driver(abx500_chargalg_driver);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:abx500-chargalg"); MODULE_ALIAS("platform:abx500-chargalg");
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define AXP209_FG_PERCENT GENMASK(6, 0) #define AXP209_FG_PERCENT GENMASK(6, 0)
#define AXP22X_FG_VALID BIT(7) #define AXP22X_FG_VALID BIT(7)
#define AXP20X_CHRG_CTRL1_ENABLE BIT(7)
#define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5) #define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5)
#define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5) #define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5)
#define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5) #define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5)
...@@ -468,7 +469,18 @@ static int axp20x_battery_set_prop(struct power_supply *psy, ...@@ -468,7 +469,18 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
return axp20x_set_max_constant_charge_current(axp20x_batt, return axp20x_set_max_constant_charge_current(axp20x_batt,
val->intval); val->intval);
case POWER_SUPPLY_PROP_STATUS:
switch (val->intval) {
case POWER_SUPPLY_STATUS_CHARGING:
return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE);
case POWER_SUPPLY_STATUS_DISCHARGING:
case POWER_SUPPLY_STATUS_NOT_CHARGING:
return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
AXP20X_CHRG_CTRL1_ENABLE, 0);
}
fallthrough;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -491,7 +503,8 @@ static enum power_supply_property axp20x_battery_props[] = { ...@@ -491,7 +503,8 @@ static enum power_supply_property axp20x_battery_props[] = {
static int axp20x_battery_prop_writeable(struct power_supply *psy, static int axp20x_battery_prop_writeable(struct power_supply *psy,
enum power_supply_property psp) enum power_supply_property psp)
{ {
return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN || return psp == POWER_SUPPLY_PROP_STATUS ||
psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
......
...@@ -142,9 +142,7 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg) ...@@ -142,9 +142,7 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg)
for (i = 0; i < NR_RETRY_CNT; i++) { for (i = 0; i < NR_RETRY_CNT; i++) {
ret = regmap_read(info->regmap, reg, &val); ret = regmap_read(info->regmap, reg, &val);
if (ret == -EBUSY) if (ret != -EBUSY)
continue;
else
break; break;
} }
...@@ -676,7 +674,7 @@ static void fuel_gauge_init_irq(struct axp288_fg_info *info) ...@@ -676,7 +674,7 @@ static void fuel_gauge_init_irq(struct axp288_fg_info *info)
* detection reports one despite it not being there. * detection reports one despite it not being there.
* Please keep this listed sorted alphabetically. * Please keep this listed sorted alphabetically.
*/ */
static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { static const struct dmi_system_id axp288_no_battery_list[] = {
{ {
/* ACEPC T8 Cherry Trail Z8350 mini PC */ /* ACEPC T8 Cherry Trail Z8350 mini PC */
.matches = { .matches = {
...@@ -723,15 +721,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { ...@@ -723,15 +721,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "MEEGOPAD T02"), DMI_MATCH(DMI_PRODUCT_NAME, "MEEGOPAD T02"),
}, },
}, },
{
/* Meegopad T08 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by OEM."),
DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
},
},
{ /* Mele PCG03 Mini PC */ { /* Mele PCG03 Mini PC */
.matches = { .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"), DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
...@@ -745,6 +734,15 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { ...@@ -745,6 +734,15 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
} }
}, },
{
/* Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
DMI_MATCH(DMI_CHASSIS_TYPE, "3"),
DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
DMI_MATCH(DMI_BIOS_VERSION, "5.11"),
},
},
{} {}
}; };
...@@ -764,7 +762,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) ...@@ -764,7 +762,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev)
}; };
unsigned int val; unsigned int val;
if (dmi_check_system(axp288_fuel_gauge_blacklist)) if (dmi_check_system(axp288_no_battery_list))
return -ENODEV; return -ENODEV;
/* /*
......
This diff is collapsed.
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
* Author: Mark A. Greer <mgreer@animalcreek.com> * Author: Mark A. Greer <mgreer@animalcreek.com>
*/ */
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of_irq.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/power/bq24190_charger.h> #include <linux/power/bq24190_charger.h>
...@@ -1959,7 +1958,6 @@ static const struct i2c_device_id bq24190_i2c_ids[] = { ...@@ -1959,7 +1958,6 @@ static const struct i2c_device_id bq24190_i2c_ids[] = {
}; };
MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
#ifdef CONFIG_OF
static const struct of_device_id bq24190_of_match[] = { static const struct of_device_id bq24190_of_match[] = {
{ .compatible = "ti,bq24190", }, { .compatible = "ti,bq24190", },
{ .compatible = "ti,bq24192", }, { .compatible = "ti,bq24192", },
...@@ -1968,11 +1966,6 @@ static const struct of_device_id bq24190_of_match[] = { ...@@ -1968,11 +1966,6 @@ static const struct of_device_id bq24190_of_match[] = {
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, bq24190_of_match); MODULE_DEVICE_TABLE(of, bq24190_of_match);
#else
static const struct of_device_id bq24190_of_match[] = {
{ },
};
#endif
static struct i2c_driver bq24190_driver = { static struct i2c_driver bq24190_driver = {
.probe = bq24190_probe, .probe = bq24190_probe,
...@@ -1981,7 +1974,7 @@ static struct i2c_driver bq24190_driver = { ...@@ -1981,7 +1974,7 @@ static struct i2c_driver bq24190_driver = {
.driver = { .driver = {
.name = "bq24190-charger", .name = "bq24190-charger",
.pm = &bq24190_pm_ops, .pm = &bq24190_pm_ops,
.of_match_table = of_match_ptr(bq24190_of_match), .of_match_table = bq24190_of_match,
}, },
}; };
module_i2c_driver(bq24190_driver); module_i2c_driver(bq24190_driver);
......
...@@ -1279,6 +1279,7 @@ static const struct of_device_id charger_manager_match[] = { ...@@ -1279,6 +1279,7 @@ static const struct of_device_id charger_manager_match[] = {
}, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, charger_manager_match);
static struct charger_desc *of_cm_parse_desc(struct device *dev) static struct charger_desc *of_cm_parse_desc(struct device *dev)
{ {
......
...@@ -667,10 +667,23 @@ static int cpcap_battery_get_property(struct power_supply *psy, ...@@ -667,10 +667,23 @@ static int cpcap_battery_get_property(struct power_supply *psy,
if (!empty->voltage) if (!empty->voltage)
return -ENODATA; return -ENODATA;
val->intval = empty->counter_uah - latest->counter_uah; val->intval = empty->counter_uah - latest->counter_uah;
if (val->intval < 0) if (val->intval < 0) {
/* Assume invalid config if CHARGE_NOW is -20% */
if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) {
empty->voltage = 0;
ddata->charge_full = 0;
return -ENODATA;
}
val->intval = 0; val->intval = 0;
else if (ddata->charge_full && ddata->charge_full < val->intval) } else if (ddata->charge_full && ddata->charge_full < val->intval) {
/* Assume invalid config if CHARGE_NOW exceeds CHARGE_FULL by 20% */
if (val->intval > (6*ddata->charge_full)/5) {
empty->voltage = 0;
ddata->charge_full = 0;
return -ENODATA;
}
val->intval = ddata->charge_full; val->intval = ddata->charge_full;
}
break; break;
case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL:
if (!ddata->charge_full) if (!ddata->charge_full)
...@@ -747,7 +760,7 @@ static int cpcap_battery_set_property(struct power_supply *psy, ...@@ -747,7 +760,7 @@ static int cpcap_battery_set_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL:
if (val->intval < 0) if (val->intval < 0)
return -EINVAL; return -EINVAL;
if (val->intval > ddata->config.info.charge_full_design) if (val->intval > (6*ddata->config.info.charge_full_design)/5)
return -EINVAL; return -EINVAL;
ddata->charge_full = val->intval; ddata->charge_full = val->intval;
......
...@@ -173,23 +173,6 @@ static enum power_supply_property cpcap_charger_props[] = { ...@@ -173,23 +173,6 @@ static enum power_supply_property cpcap_charger_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_NOW,
}; };
/* No battery always shows temperature of -40000 */
static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
{
struct iio_channel *channel;
int error, temperature;
channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
error = iio_read_channel_processed(channel, &temperature);
if (error < 0) {
dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
return false;
}
return temperature > -20000 && temperature < 60000;
}
static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata) static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
{ {
struct iio_channel *channel; struct iio_channel *channel;
...@@ -700,11 +683,29 @@ static void cpcap_usb_detect(struct work_struct *work) ...@@ -700,11 +683,29 @@ static void cpcap_usb_detect(struct work_struct *work)
if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) && if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
s.chrgcurr1) { s.chrgcurr1) {
int max_current = 532000; int max_current;
int vchrg, ichrg; int vchrg, ichrg;
union power_supply_propval val;
struct power_supply *battery;
battery = power_supply_get_by_name("battery");
if (IS_ERR_OR_NULL(battery)) {
dev_err(ddata->dev, "battery power_supply not available %li\n",
PTR_ERR(battery));
return;
}
if (cpcap_charger_battery_found(ddata)) error = power_supply_get_property(battery, POWER_SUPPLY_PROP_PRESENT, &val);
power_supply_put(battery);
if (error)
goto out_err;
if (val.intval) {
max_current = 1596000; max_current = 1596000;
} else {
dev_info(ddata->dev, "battery not inserted, charging disabled\n");
max_current = 0;
}
if (max_current > ddata->limit_current) if (max_current > ddata->limit_current)
max_current = ddata->limit_current; max_current = ddata->limit_current;
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/max17040_battery.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -142,13 +141,10 @@ struct max17040_chip { ...@@ -142,13 +141,10 @@ struct max17040_chip {
struct regmap *regmap; struct regmap *regmap;
struct delayed_work work; struct delayed_work work;
struct power_supply *battery; struct power_supply *battery;
struct max17040_platform_data *pdata;
struct chip_data data; struct chip_data data;
/* battery capacity */ /* battery capacity */
int soc; int soc;
/* State Of Charge */
int status;
/* Low alert threshold from 32% to 1% of the State of Charge */ /* Low alert threshold from 32% to 1% of the State of Charge */
u32 low_soc_alert; u32 low_soc_alert;
/* some devices return twice the capacity */ /* some devices return twice the capacity */
...@@ -221,26 +217,7 @@ static int max17040_get_version(struct max17040_chip *chip) ...@@ -221,26 +217,7 @@ static int max17040_get_version(struct max17040_chip *chip)
static int max17040_get_online(struct max17040_chip *chip) static int max17040_get_online(struct max17040_chip *chip)
{ {
return chip->pdata && chip->pdata->battery_online ? return 1;
chip->pdata->battery_online() : 1;
}
static int max17040_get_status(struct max17040_chip *chip)
{
if (!chip->pdata || !chip->pdata->charger_online
|| !chip->pdata->charger_enable)
return POWER_SUPPLY_STATUS_UNKNOWN;
if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
return POWER_SUPPLY_STATUS_FULL;
if (chip->pdata->charger_online())
if (chip->pdata->charger_enable())
return POWER_SUPPLY_STATUS_CHARGING;
else
return POWER_SUPPLY_STATUS_NOT_CHARGING;
else
return POWER_SUPPLY_STATUS_DISCHARGING;
} }
static int max17040_get_of_data(struct max17040_chip *chip) static int max17040_get_of_data(struct max17040_chip *chip)
...@@ -283,7 +260,6 @@ static int max17040_get_of_data(struct max17040_chip *chip) ...@@ -283,7 +260,6 @@ static int max17040_get_of_data(struct max17040_chip *chip)
static void max17040_check_changes(struct max17040_chip *chip) static void max17040_check_changes(struct max17040_chip *chip)
{ {
chip->soc = max17040_get_soc(chip); chip->soc = max17040_get_soc(chip);
chip->status = max17040_get_status(chip);
} }
static void max17040_queue_work(struct max17040_chip *chip) static void max17040_queue_work(struct max17040_chip *chip)
...@@ -302,17 +278,16 @@ static void max17040_stop_work(void *data) ...@@ -302,17 +278,16 @@ static void max17040_stop_work(void *data)
static void max17040_work(struct work_struct *work) static void max17040_work(struct work_struct *work)
{ {
struct max17040_chip *chip; struct max17040_chip *chip;
int last_soc, last_status; int last_soc;
chip = container_of(work, struct max17040_chip, work.work); chip = container_of(work, struct max17040_chip, work.work);
/* store SOC and status to check changes */ /* store SOC to check changes */
last_soc = chip->soc; last_soc = chip->soc;
last_status = chip->status;
max17040_check_changes(chip); max17040_check_changes(chip);
/* check changes and send uevent */ /* check changes and send uevent */
if (last_soc != chip->soc || last_status != chip->status) if (last_soc != chip->soc)
power_supply_changed(chip->battery); power_supply_changed(chip->battery);
max17040_queue_work(chip); max17040_queue_work(chip);
...@@ -361,12 +336,10 @@ static irqreturn_t max17040_thread_handler(int id, void *dev) ...@@ -361,12 +336,10 @@ static irqreturn_t max17040_thread_handler(int id, void *dev)
static int max17040_enable_alert_irq(struct max17040_chip *chip) static int max17040_enable_alert_irq(struct max17040_chip *chip)
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
unsigned int flags;
int ret; int ret;
flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
max17040_thread_handler, flags, max17040_thread_handler, IRQF_ONESHOT,
chip->battery->desc->name, chip); chip->battery->desc->name, chip);
return ret; return ret;
...@@ -415,9 +388,6 @@ static int max17040_get_property(struct power_supply *psy, ...@@ -415,9 +388,6 @@ static int max17040_get_property(struct power_supply *psy,
struct max17040_chip *chip = power_supply_get_drvdata(psy); struct max17040_chip *chip = power_supply_get_drvdata(psy);
switch (psp) { switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = max17040_get_status(chip);
break;
case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_ONLINE:
val->intval = max17040_get_online(chip); val->intval = max17040_get_online(chip);
break; break;
...@@ -444,7 +414,6 @@ static const struct regmap_config max17040_regmap = { ...@@ -444,7 +414,6 @@ static const struct regmap_config max17040_regmap = {
}; };
static enum power_supply_property max17040_battery_props[] = { static enum power_supply_property max17040_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY,
...@@ -480,7 +449,6 @@ static int max17040_probe(struct i2c_client *client, ...@@ -480,7 +449,6 @@ static int max17040_probe(struct i2c_client *client,
chip->client = client; chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap); chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
chip->pdata = client->dev.platform_data;
chip_id = (enum chip_id) id->driver_data; chip_id = (enum chip_id) id->driver_data;
if (client->dev.of_node) { if (client->dev.of_node) {
ret = max17040_get_of_data(chip); ret = max17040_get_of_data(chip);
......
...@@ -1104,7 +1104,7 @@ static int max17042_probe(struct i2c_client *client, ...@@ -1104,7 +1104,7 @@ static int max17042_probe(struct i2c_client *client,
} }
if (client->irq) { if (client->irq) {
unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; unsigned int flags = IRQF_ONESHOT;
/* /*
* On ACPI systems the IRQ may be handled by ACPI-event code, * On ACPI systems the IRQ may be handled by ACPI-event code,
......
This diff is collapsed.
...@@ -37,8 +37,27 @@ ...@@ -37,8 +37,27 @@
#define CHG_STATE_NO_BAT2 13 #define CHG_STATE_NO_BAT2 13
#define CHG_STATE_CHG_READY_VUSB 14 #define CHG_STATE_CHG_READY_VUSB 14
#define GCHGDET_TYPE_MASK 0x30
#define GCHGDET_TYPE_SDP 0x00
#define GCHGDET_TYPE_CDP 0x10
#define GCHGDET_TYPE_DCP 0x20
#define FG_ENABLE 1 #define FG_ENABLE 1
/*
* Formula seems accurate for battery current, but for USB current around 70mA
* per step was seen on Kobo Clara HD but all sources show the same formula
* also fur USB current. To avoid accidentially unwanted high currents we stick
* to that formula
*/
#define TO_CUR_REG(x) ((x) / 100000 - 1)
#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
#define CHG_MIN_CUR 100000
#define CHG_MAX_CUR 1800000
#define ADP_MAX_CUR 2500000
#define USB_MAX_CUR 1400000
struct rn5t618_power_info { struct rn5t618_power_info {
struct rn5t618 *rn5t618; struct rn5t618 *rn5t618;
struct platform_device *pdev; struct platform_device *pdev;
...@@ -48,12 +67,24 @@ struct rn5t618_power_info { ...@@ -48,12 +67,24 @@ struct rn5t618_power_info {
int irq; int irq;
}; };
static enum power_supply_usb_type rn5t618_usb_types[] = {
POWER_SUPPLY_USB_TYPE_SDP,
POWER_SUPPLY_USB_TYPE_DCP,
POWER_SUPPLY_USB_TYPE_CDP,
POWER_SUPPLY_USB_TYPE_UNKNOWN
};
static enum power_supply_property rn5t618_usb_props[] = { static enum power_supply_property rn5t618_usb_props[] = {
/* input current limit is not very accurate */
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_ONLINE,
}; };
static enum power_supply_property rn5t618_adp_props[] = { static enum power_supply_property rn5t618_adp_props[] = {
/* input current limit is not very accurate */
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_ONLINE,
}; };
...@@ -69,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = { ...@@ -69,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_NOW,
}; };
...@@ -258,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info, ...@@ -258,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
return 0; return 0;
} }
static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
const union power_supply_propval *val)
{
if (val->intval < CHG_MIN_CUR)
return -EINVAL;
if (val->intval >= CHG_MAX_CUR)
return -EINVAL;
return regmap_update_bits(info->rn5t618->regmap,
RN5T618_CHGISET,
0x1F, TO_CUR_REG(val->intval));
}
static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
unsigned int regval;
int ret;
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
&regval);
if (ret < 0)
return ret;
val->intval = FROM_CUR_REG(regval);
return 0;
}
static int rn5t618_battery_charge_full(struct rn5t618_power_info *info, static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
union power_supply_propval *val) union power_supply_propval *val)
{ {
...@@ -323,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy, ...@@ -323,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TECHNOLOGY: case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION; val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break; break;
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
ret = rn5t618_battery_get_current_limit(info, val);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = rn5t618_battery_charge_full(info, val); ret = rn5t618_battery_charge_full(info, val);
break; break;
...@@ -336,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy, ...@@ -336,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
return ret; return ret;
} }
static int rn5t618_battery_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return rn5t618_battery_set_current_limit(info, val);
default:
return -EINVAL;
}
}
static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return true;
default:
return false;
}
}
static int rn5t618_adp_get_property(struct power_supply *psy, static int rn5t618_adp_get_property(struct power_supply *psy,
enum power_supply_property psp, enum power_supply_property psp,
union power_supply_propval *val) union power_supply_propval *val)
{ {
struct rn5t618_power_info *info = power_supply_get_drvdata(psy); struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate; unsigned int chgstate;
unsigned int regval;
bool online; bool online;
int ret; int ret;
...@@ -364,6 +455,42 @@ static int rn5t618_adp_get_property(struct power_supply *psy, ...@@ -364,6 +455,42 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
if (val->intval != POWER_SUPPLY_STATUS_CHARGING) if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(info->rn5t618->regmap,
RN5T618_REGISET1, &regval);
if (ret < 0)
return ret;
val->intval = FROM_CUR_REG(regval);
break;
default:
return -EINVAL;
}
return 0;
}
static int rn5t618_adp_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (val->intval > ADP_MAX_CUR)
return -EINVAL;
if (val->intval < CHG_MIN_CUR)
return -EINVAL;
ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
TO_CUR_REG(val->intval));
if (ret < 0)
return ret;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -372,12 +499,51 @@ static int rn5t618_adp_get_property(struct power_supply *psy, ...@@ -372,12 +499,51 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
return 0; return 0;
} }
static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
return false;
}
}
static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
unsigned int regval;
int ret;
ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
if (ret < 0)
return ret;
switch (regval & GCHGDET_TYPE_MASK) {
case GCHGDET_TYPE_SDP:
val->intval = POWER_SUPPLY_USB_TYPE_SDP;
break;
case GCHGDET_TYPE_CDP:
val->intval = POWER_SUPPLY_USB_TYPE_CDP;
break;
case GCHGDET_TYPE_DCP:
val->intval = POWER_SUPPLY_USB_TYPE_DCP;
break;
default:
val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
}
return 0;
}
static int rn5t618_usb_get_property(struct power_supply *psy, static int rn5t618_usb_get_property(struct power_supply *psy,
enum power_supply_property psp, enum power_supply_property psp,
union power_supply_propval *val) union power_supply_propval *val)
{ {
struct rn5t618_power_info *info = power_supply_get_drvdata(psy); struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate; unsigned int chgstate;
unsigned int regval;
bool online; bool online;
int ret; int ret;
...@@ -400,6 +566,56 @@ static int rn5t618_usb_get_property(struct power_supply *psy, ...@@ -400,6 +566,56 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
if (val->intval != POWER_SUPPLY_STATUS_CHARGING) if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
case POWER_SUPPLY_PROP_USB_TYPE:
if (!online || (info->rn5t618->variant != RC5T619))
return -ENODATA;
return rc5t619_usb_get_type(info, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
&regval);
if (ret < 0)
return ret;
val->intval = 0;
if (regval & 2) {
ret = regmap_read(info->rn5t618->regmap,
RN5T618_REGISET2,
&regval);
if (ret < 0)
return ret;
val->intval = FROM_CUR_REG(regval);
}
break;
default:
return -EINVAL;
}
return 0;
}
static int rn5t618_usb_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (val->intval > USB_MAX_CUR)
return -EINVAL;
if (val->intval < CHG_MIN_CUR)
return -EINVAL;
ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
0xE0 | TO_CUR_REG(val->intval));
if (ret < 0)
return ret;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -408,12 +624,25 @@ static int rn5t618_usb_get_property(struct power_supply *psy, ...@@ -408,12 +624,25 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
return 0; return 0;
} }
static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
return false;
}
}
static const struct power_supply_desc rn5t618_battery_desc = { static const struct power_supply_desc rn5t618_battery_desc = {
.name = "rn5t618-battery", .name = "rn5t618-battery",
.type = POWER_SUPPLY_TYPE_BATTERY, .type = POWER_SUPPLY_TYPE_BATTERY,
.properties = rn5t618_battery_props, .properties = rn5t618_battery_props,
.num_properties = ARRAY_SIZE(rn5t618_battery_props), .num_properties = ARRAY_SIZE(rn5t618_battery_props),
.get_property = rn5t618_battery_get_property, .get_property = rn5t618_battery_get_property,
.set_property = rn5t618_battery_set_property,
.property_is_writeable = rn5t618_battery_property_is_writeable,
}; };
static const struct power_supply_desc rn5t618_adp_desc = { static const struct power_supply_desc rn5t618_adp_desc = {
...@@ -422,14 +651,20 @@ static const struct power_supply_desc rn5t618_adp_desc = { ...@@ -422,14 +651,20 @@ static const struct power_supply_desc rn5t618_adp_desc = {
.properties = rn5t618_adp_props, .properties = rn5t618_adp_props,
.num_properties = ARRAY_SIZE(rn5t618_adp_props), .num_properties = ARRAY_SIZE(rn5t618_adp_props),
.get_property = rn5t618_adp_get_property, .get_property = rn5t618_adp_get_property,
.set_property = rn5t618_adp_set_property,
.property_is_writeable = rn5t618_adp_property_is_writeable,
}; };
static const struct power_supply_desc rn5t618_usb_desc = { static const struct power_supply_desc rn5t618_usb_desc = {
.name = "rn5t618-usb", .name = "rn5t618-usb",
.type = POWER_SUPPLY_TYPE_USB, .type = POWER_SUPPLY_TYPE_USB,
.usb_types = rn5t618_usb_types,
.num_usb_types = ARRAY_SIZE(rn5t618_usb_types),
.properties = rn5t618_usb_props, .properties = rn5t618_usb_props,
.num_properties = ARRAY_SIZE(rn5t618_usb_props), .num_properties = ARRAY_SIZE(rn5t618_usb_props),
.get_property = rn5t618_usb_get_property, .get_property = rn5t618_usb_get_property,
.set_property = rn5t618_usb_set_property,
.property_is_writeable = rn5t618_usb_property_is_writeable,
}; };
static irqreturn_t rn5t618_charger_irq(int irq, void *data) static irqreturn_t rn5t618_charger_irq(int irq, void *data)
......
...@@ -164,9 +164,16 @@ static const struct i2c_device_id rt5033_battery_id[] = { ...@@ -164,9 +164,16 @@ static const struct i2c_device_id rt5033_battery_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); MODULE_DEVICE_TABLE(i2c, rt5033_battery_id);
static const struct of_device_id rt5033_battery_of_match[] = {
{ .compatible = "richtek,rt5033-battery", },
{ }
};
MODULE_DEVICE_TABLE(of, rt5033_battery_of_match);
static struct i2c_driver rt5033_battery_driver = { static struct i2c_driver rt5033_battery_driver = {
.driver = { .driver = {
.name = "rt5033-battery", .name = "rt5033-battery",
.of_match_table = rt5033_battery_of_match,
}, },
.probe = rt5033_battery_probe, .probe = rt5033_battery_probe,
.remove = rt5033_battery_remove, .remove = rt5033_battery_remove,
......
...@@ -189,6 +189,14 @@ static const enum power_supply_property sbs_properties[] = { ...@@ -189,6 +189,14 @@ static const enum power_supply_property sbs_properties[] = {
/* Supports special manufacturer commands from TI BQ20Z65 and BQ20Z75 IC. */ /* Supports special manufacturer commands from TI BQ20Z65 and BQ20Z75 IC. */
#define SBS_FLAGS_TI_BQ20ZX5 BIT(0) #define SBS_FLAGS_TI_BQ20ZX5 BIT(0)
static const enum power_supply_property string_properties[] = {
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_MODEL_NAME,
};
#define NR_STRING_BUFFERS ARRAY_SIZE(string_properties)
struct sbs_info { struct sbs_info {
struct i2c_client *client; struct i2c_client *client;
struct power_supply *power_supply; struct power_supply *power_supply;
...@@ -202,11 +210,32 @@ struct sbs_info { ...@@ -202,11 +210,32 @@ struct sbs_info {
struct delayed_work work; struct delayed_work work;
struct mutex mode_lock; struct mutex mode_lock;
u32 flags; u32 flags;
int technology;
char strings[NR_STRING_BUFFERS][I2C_SMBUS_BLOCK_MAX + 1];
}; };
static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; static char *sbs_get_string_buf(struct sbs_info *chip,
static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1]; enum power_supply_property psp)
static char chemistry[I2C_SMBUS_BLOCK_MAX + 1]; {
int i = 0;
for (i = 0; i < NR_STRING_BUFFERS; i++)
if (string_properties[i] == psp)
return chip->strings[i];
return ERR_PTR(-EINVAL);
}
static void sbs_invalidate_cached_props(struct sbs_info *chip)
{
int i = 0;
chip->technology = -1;
for (i = 0; i < NR_STRING_BUFFERS; i++)
chip->strings[i][0] = 0;
}
static bool force_load; static bool force_load;
static int sbs_read_word_data(struct i2c_client *client, u8 address); static int sbs_read_word_data(struct i2c_client *client, u8 address);
...@@ -244,6 +273,7 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present) ...@@ -244,6 +273,7 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present)
chip->is_present = false; chip->is_present = false;
/* Disable PEC when no device is present */ /* Disable PEC when no device is present */
client->flags &= ~I2C_CLIENT_PEC; client->flags &= ~I2C_CLIENT_PEC;
sbs_invalidate_cached_props(chip);
return 0; return 0;
} }
...@@ -640,17 +670,45 @@ static int sbs_get_battery_property(struct i2c_client *client, ...@@ -640,17 +670,45 @@ static int sbs_get_battery_property(struct i2c_client *client,
return 0; return 0;
} }
static int sbs_get_battery_string_property(struct i2c_client *client, static int sbs_get_property_index(struct i2c_client *client,
int reg_offset, enum power_supply_property psp, char *val) enum power_supply_property psp)
{ {
s32 ret; int count;
for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
if (psp == sbs_data[count].psp)
return count;
ret = sbs_read_string_data(client, sbs_data[reg_offset].addr, val); dev_warn(&client->dev,
"%s: Invalid Property - %d\n", __func__, psp);
return -EINVAL;
}
static const char *sbs_get_constant_string(struct sbs_info *chip,
enum power_supply_property psp)
{
int ret;
char *buf;
u8 addr;
buf = sbs_get_string_buf(chip, psp);
if (IS_ERR(buf))
return buf;
if (!buf[0]) {
ret = sbs_get_property_index(chip->client, psp);
if (ret < 0) if (ret < 0)
return ret; return ERR_PTR(ret);
return 0; addr = sbs_data[ret].addr;
ret = sbs_read_string_data(chip->client, addr, buf);
if (ret < 0)
return ERR_PTR(ret);
}
return buf;
} }
static void sbs_unit_adjustment(struct i2c_client *client, static void sbs_unit_adjustment(struct i2c_client *client,
...@@ -773,48 +831,36 @@ static int sbs_get_battery_serial_number(struct i2c_client *client, ...@@ -773,48 +831,36 @@ static int sbs_get_battery_serial_number(struct i2c_client *client,
return 0; return 0;
} }
static int sbs_get_property_index(struct i2c_client *client, static int sbs_get_chemistry(struct sbs_info *chip,
enum power_supply_property psp)
{
int count;
for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
if (psp == sbs_data[count].psp)
return count;
dev_warn(&client->dev,
"%s: Invalid Property - %d\n", __func__, psp);
return -EINVAL;
}
static int sbs_get_chemistry(struct i2c_client *client,
union power_supply_propval *val) union power_supply_propval *val)
{ {
enum power_supply_property psp = POWER_SUPPLY_PROP_TECHNOLOGY; const char *chemistry;
int ret;
ret = sbs_get_property_index(client, psp); if (chip->technology != -1) {
if (ret < 0) val->intval = chip->technology;
return ret; return 0;
}
ret = sbs_get_battery_string_property(client, ret, psp, chemistry = sbs_get_constant_string(chip, POWER_SUPPLY_PROP_TECHNOLOGY);
chemistry);
if (ret < 0) if (IS_ERR(chemistry))
return ret; return PTR_ERR(chemistry);
if (!strncasecmp(chemistry, "LION", 4)) if (!strncasecmp(chemistry, "LION", 4))
val->intval = POWER_SUPPLY_TECHNOLOGY_LION; chip->technology = POWER_SUPPLY_TECHNOLOGY_LION;
else if (!strncasecmp(chemistry, "LiP", 3)) else if (!strncasecmp(chemistry, "LiP", 3))
val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; chip->technology = POWER_SUPPLY_TECHNOLOGY_LIPO;
else if (!strncasecmp(chemistry, "NiCd", 4)) else if (!strncasecmp(chemistry, "NiCd", 4))
val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd; chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd;
else if (!strncasecmp(chemistry, "NiMH", 4)) else if (!strncasecmp(chemistry, "NiMH", 4))
val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH;
else else
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
if (chip->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
dev_warn(&chip->client->dev, "Unknown chemistry: %s\n", chemistry);
if (val->intval == POWER_SUPPLY_TECHNOLOGY_UNKNOWN) val->intval = chip->technology;
dev_warn(&client->dev, "Unknown chemistry: %s\n", chemistry);
return 0; return 0;
} }
...@@ -858,6 +904,7 @@ static int sbs_get_property(struct power_supply *psy, ...@@ -858,6 +904,7 @@ static int sbs_get_property(struct power_supply *psy,
int ret = 0; int ret = 0;
struct sbs_info *chip = power_supply_get_drvdata(psy); struct sbs_info *chip = power_supply_get_drvdata(psy);
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
const char *str;
if (chip->gpio_detect) { if (chip->gpio_detect) {
ret = gpiod_get_value_cansleep(chip->gpio_detect); ret = gpiod_get_value_cansleep(chip->gpio_detect);
...@@ -883,7 +930,7 @@ static int sbs_get_property(struct power_supply *psy, ...@@ -883,7 +930,7 @@ static int sbs_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_TECHNOLOGY: case POWER_SUPPLY_PROP_TECHNOLOGY:
ret = sbs_get_chemistry(client, val); ret = sbs_get_chemistry(chip, val);
if (ret < 0) if (ret < 0)
break; break;
...@@ -935,23 +982,12 @@ static int sbs_get_property(struct power_supply *psy, ...@@ -935,23 +982,12 @@ static int sbs_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_MODEL_NAME: case POWER_SUPPLY_PROP_MODEL_NAME:
ret = sbs_get_property_index(client, psp);
if (ret < 0)
break;
ret = sbs_get_battery_string_property(client, ret, psp,
model_name);
val->strval = model_name;
break;
case POWER_SUPPLY_PROP_MANUFACTURER: case POWER_SUPPLY_PROP_MANUFACTURER:
ret = sbs_get_property_index(client, psp); str = sbs_get_constant_string(chip, psp);
if (ret < 0) if (IS_ERR(str))
break; ret = PTR_ERR(str);
else
ret = sbs_get_battery_string_property(client, ret, psp, val->strval = str;
manufacturer);
val->strval = manufacturer;
break; break;
case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
...@@ -1098,6 +1134,7 @@ static int sbs_probe(struct i2c_client *client) ...@@ -1098,6 +1134,7 @@ static int sbs_probe(struct i2c_client *client)
psy_cfg.of_node = client->dev.of_node; psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = chip; psy_cfg.drv_data = chip;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN; chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
sbs_invalidate_cached_props(chip);
mutex_init(&chip->mode_lock); mutex_init(&chip->mode_lock);
/* use pdata if available, fall back to DT properties, /* use pdata if available, fall back to DT properties,
......
...@@ -524,6 +524,7 @@ static const struct of_device_id sc2731_charger_of_match[] = { ...@@ -524,6 +524,7 @@ static const struct of_device_id sc2731_charger_of_match[] = {
{ .compatible = "sprd,sc2731-charger", }, { .compatible = "sprd,sc2731-charger", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, sc2731_charger_of_match);
static struct platform_driver sc2731_charger_driver = { static struct platform_driver sc2731_charger_driver = {
.driver = { .driver = {
......
...@@ -1342,6 +1342,7 @@ static const struct of_device_id sc27xx_fgu_of_match[] = { ...@@ -1342,6 +1342,7 @@ static const struct of_device_id sc27xx_fgu_of_match[] = {
{ .compatible = "sprd,sc2731-fgu", }, { .compatible = "sprd,sc2731-fgu", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, sc27xx_fgu_of_match);
static struct platform_driver sc27xx_fgu_driver = { static struct platform_driver sc27xx_fgu_driver = {
.probe = sc27xx_fgu_probe, .probe = sc27xx_fgu_probe,
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -345,6 +345,16 @@ static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_eve ...@@ -345,6 +345,16 @@ static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_eve
struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif); struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);
int status; int status;
/*
* We cannot use strict matching when registering the notifier as the
* EC expects us to register it against instance ID 0. Strict matching
* would thus drop events, as those may have non-zero instance IDs in
* this subsystem. So we need to check the instance ID of the event
* here manually.
*/
if (event->instance_id != bat->sdev->uid.instance)
return 0;
dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n", dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
event->command_id, event->instance_id, event->target_id); event->command_id, event->instance_id, event->target_id);
...@@ -720,8 +730,8 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic ...@@ -720,8 +730,8 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic
bat->notif.base.fn = spwr_notify_bat; bat->notif.base.fn = spwr_notify_bat;
bat->notif.event.reg = registry; bat->notif.event.reg = registry;
bat->notif.event.id.target_category = sdev->uid.category; bat->notif.event.id.target_category = sdev->uid.category;
bat->notif.event.id.instance = 0; bat->notif.event.id.instance = 0; /* need to register with instance 0 */
bat->notif.event.mask = SSAM_EVENT_MASK_STRICT; bat->notif.event.mask = SSAM_EVENT_MASK_TARGET;
bat->notif.event.flags = SSAM_EVENT_SEQUENCED; bat->notif.event.flags = SSAM_EVENT_SEQUENCED;
bat->psy_desc.name = bat->name; bat->psy_desc.name = bat->name;
......
...@@ -66,7 +66,7 @@ struct spwr_ac_device { ...@@ -66,7 +66,7 @@ struct spwr_ac_device {
static int spwr_ac_update_unlocked(struct spwr_ac_device *ac) static int spwr_ac_update_unlocked(struct spwr_ac_device *ac)
{ {
u32 old = ac->state; __le32 old = ac->state;
int status; int status;
lockdep_assert_held(&ac->lock); lockdep_assert_held(&ac->lock);
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2009 Samsung Electronics
* Minkyu Kang <mk7.kang@samsung.com>
*/
#ifndef __MAX17040_BATTERY_H_
#define __MAX17040_BATTERY_H_
struct max17040_platform_data {
int (*battery_online)(void);
int (*charger_online)(void);
int (*charger_enable)(void);
};
#endif
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* PM2301 charger driver.
*
* Copyright (C) 2012 ST Ericsson Corporation
*
* Contact: Olivier LAUNAY (olivier.launay@stericsson.com
*/
#ifndef __LINUX_PM2301_H
#define __LINUX_PM2301_H
/**
* struct pm2xxx_bm_charger_parameters - Charger specific parameters
* @ac_volt_max: maximum allowed AC charger voltage in mV
* @ac_curr_max: maximum allowed AC charger current in mA
*/
struct pm2xxx_bm_charger_parameters {
int ac_volt_max;
int ac_curr_max;
};
/**
* struct pm2xxx_bm_data - pm2xxx battery management data
* @enable_overshoot flag to enable VBAT overshoot control
* @chg_params charger parameters
*/
struct pm2xxx_bm_data {
bool enable_overshoot;
const struct pm2xxx_bm_charger_parameters *chg_params;
};
struct pm2xxx_charger_platform_data {
char **supplied_to;
size_t num_supplicants;
int i2c_bus;
const char *label;
int gpio_irq_number;
unsigned int lpn_gpio;
int irq_type;
};
struct pm2xxx_platform_data {
struct pm2xxx_charger_platform_data *wall_charger;
struct pm2xxx_bm_data *battery;
};
#endif /* __LINUX_PM2301_H */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) ST-Ericsson 2013
* Author: Hongbo Zhang <hongbo.zhang@linaro.com>
*/
#ifndef PWR_AB8500_H
#define PWR_AB8500_H
extern const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[];
extern const int ab8500_temp_tbl_a_size;
extern const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[];
extern const int ab8500_temp_tbl_b_size;
#endif /* PWR_AB8500_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment