power supply and reset changes for the v6.3 series
- power-supply core: remove faulty cooling logic - convert all sysfs show() handlers from *printf() use sysfs_emit() - bq25890: add dual-charger support required by Lenovo Yoga Tab 3 Pro - bq27xxx: fix reporting critical level - syscon-reboot: add priority property support - Introduce new rt9467 charger driver - Introduce new rt9471 charger driver - Introduce new Odroid Go Ultra poweroff driver - misc. minor fixes and cleanups -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmP2liwACgkQ2O7X88g7 +pqIYhAAn+V42O7Yf3w2FuUlxRvDUKfwi0V9LDWtHTxMQPR9WRZm2nHLJD2Ce4Ac 9I8ZacQMfjLnKV+cP6QH7Q30QVNmqSlAdMa54sgACOY/M/eFjLVaNr56mhwFWPKN Z2Cel8ey87OpsxHHJ/9QrMuppVMGhv6VCtoLnvOWQ2PslTRIdoVlMxIhr5Ur047S hoHc3t9J5K1GX/j24g6ed7Iu9MZpag0lKfxDenVLqfFfoSdoDfWEdRQejtECfLjo Z7TtfvG3NBdJXlGOn/E475h/V5RDAckQw/se3m/GpCIk2YzY1Bg4V1PhR+wxPj07 LT/DF5rfk8i9WflaUM9jQwhkZWzE8JqoH1Tsik5Yqbl15t389Vmef7Fh2pkMgxIF dyAzm2N3BhnA2ibUUW96n6swi/+VxbuFVde3xgc3nUx6Ug42FwN+PUnqTgwNp6GM h0oU/1xbflTlWD27Cu5ub77Y/CNg2TL06CKeLLi4CEs/Ldf2TDeviVZbNsAibasA bNBcDzHgs5jTH1FLAA79YKmbFbJWcM6rG0MA6KvzhNj/39eW/I99ehOScA3moIgN JdCZ3bCN0JQbTwt1QzUsT575F//QGLhYNeXrH9pG33EaXqpn4WRVN9ukxmLMSMBA UzmNGo7TUjofrDbh431XxDKcLmBaQZ9UFy0Z4lH6u+3B1nZ66RA= =bdNo -----END PGP SIGNATURE----- Merge tag 'for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Nothing special for the power-supply subystem this time. - power-supply core: remove faulty cooling logic - convert all sysfs show() handlers from *printf() use sysfs_emit() - bq25890: add dual-charger support required by Lenovo Yoga Tab 3 Pro - bq27xxx: fix reporting critical level - syscon-reboot: add priority property support - new rt9467 charger driver - new rt9471 charger driver - new Odroid Go Ultra poweroff driver - misc minor fixes and cleanups" * tag 'for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (32 commits) power: reset: odroid-go-ultra: fix I2C dependency power: supply: leds: explicitly include linux/leds.h dt-bindings: power: supply: pm8941-coincell: Don't require charging properties dt-bindings: power: supply: pm8941-coincell: Add PM8998 compatible power: reset: add Odroid Go Ultra poweroff driver power: supply: rt9467: Fix spelling mistake "attache" -> "attach" power: supply: rt9471: fix using wrong ce_gpio in rt9471_probe() power: supply: max77650: Make max77650_charger_disable() return void Documentation: power: rt9467: Document exported sysfs entries power: supply: rt9467: Add Richtek RT9467 charger driver dt-bindings: power: supply: Add Richtek RT9467 battery charger Documentation: power: rt9471: Document exported sysfs entries power: supply: rt9471: Add Richtek RT9471 charger driver dt-bindings: power: supply: Add Richtek RT9471 battery charger power: supply: max1721x: Use strscpy() is more robust and safer power: supply: test-power: use strscpy() instead of strncpy() power: supply: bq27xxx: fix reporting critical level power: supply: bq256xx: Init ichg/vbat value with chip default value power: supply: collie_battery: Convert to GPIO descriptors (part 2) power: supply: remove faulty cooling logic ...
This commit is contained in:
commit
39f013440d
|
@ -0,0 +1,19 @@
|
|||
What: /sys/class/power_supply/rt9467-*/sysoff_enable
|
||||
Date: Feb 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: ChiaEn Wu <chiaen_wu@richtek.com>
|
||||
Description:
|
||||
This entry allows enabling the sysoff mode of rt9467 charger
|
||||
devices.
|
||||
If enabled and the input is removed, the internal battery FET
|
||||
is turned off to reduce the leakage from the BAT pin. See
|
||||
device datasheet for details. It's commonly used when the
|
||||
product enter shipping stage. After entering shipping mode,
|
||||
only 'VBUS' or 'Power key" pressed can make it leave this mode.
|
||||
'Disable' also can help to leave it, but it's more like to
|
||||
abort the action before the device really enter shipping mode.
|
||||
|
||||
Access: Read, Write
|
||||
Valid values:
|
||||
- 1: enabled
|
||||
- 0: disabled
|
|
@ -0,0 +1,32 @@
|
|||
What: /sys/class/power_supply/rt9471-*/sysoff_enable
|
||||
Date: Feb 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: ChiYuan Huang <cy_huang@richtek.com>
|
||||
Description:
|
||||
This entry allows enabling the sysoff mode of rt9471 charger devices.
|
||||
If enabled and the input is removed, the internal battery FET is turned
|
||||
off to reduce the leakage from the BAT pin. See device datasheet for details.
|
||||
It's commonly used when the product enter shipping stage. After entering
|
||||
shipping mode, only 'VBUS' or 'Power key" pressed can make it leave this
|
||||
mode. 'Disable' also can help to leave it, but it's more like to abort
|
||||
the action before the device really enter shipping mode.
|
||||
|
||||
Access: Read, Write
|
||||
Valid values:
|
||||
- 1: enabled
|
||||
- 0: disabled
|
||||
|
||||
What: /sys/class/power_supply/rt9471-*/port_detect_enable
|
||||
Date: Feb 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: ChiYuan Huang <cy_huang@richtek.com>
|
||||
Description:
|
||||
This entry allows enabling the USB BC12 port detect function of rt9471 charger
|
||||
devices. If enabled and VBUS is inserted, device will start to do the BC12
|
||||
port detect and report the usb port type when port detect is done. See
|
||||
datasheet for details. Normally controlled when TypeC/USBPD port integrated.
|
||||
|
||||
Access: Read, Write
|
||||
Valid values:
|
||||
- 1: enabled
|
||||
- 0: disabled
|
|
@ -42,6 +42,9 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: The reset value written to the reboot register (32 bit access).
|
||||
|
||||
priority:
|
||||
default: 192
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- offset
|
||||
|
@ -49,6 +52,7 @@ required:
|
|||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- $ref: restart-handler.yaml#
|
||||
- if:
|
||||
not:
|
||||
required:
|
||||
|
|
|
@ -16,18 +16,30 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,pm8941-coincell
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,pm8998-coincell
|
||||
- const: qcom,pm8941-coincell
|
||||
|
||||
- const: qcom,pm8941-coincell
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
qcom,rset-ohms:
|
||||
description: resistance (in ohms) for current-limiting resistor
|
||||
description: |
|
||||
Resistance (in ohms) for current-limiting resistor. If unspecified,
|
||||
inherit the previous configuration (e.g. from bootloader or hardware
|
||||
default value).
|
||||
enum: [ 800, 1200, 1700, 2100 ]
|
||||
|
||||
qcom,vset-millivolts:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: voltage (in millivolts) to apply for charging
|
||||
description: |
|
||||
Voltage (in millivolts) to apply for charging. If unspecified, inherit
|
||||
the previous configuration (e.g. from bootloader or hardware default
|
||||
value).
|
||||
enum: [ 2500, 3000, 3100, 3200 ]
|
||||
|
||||
qcom,charger-disable:
|
||||
|
@ -37,8 +49,6 @@ properties:
|
|||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- qcom,rset-ohms
|
||||
- qcom,vset-millivolts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/richtek,rt9467-charger.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Richtek RT9467 Switching Battery Charger with Power Path Management
|
||||
|
||||
maintainers:
|
||||
- ChiYuan Huang <cy_huang@richtek.com>
|
||||
- ChiaEn Wu <chiaen_wu@richtek.com>
|
||||
|
||||
description: |
|
||||
RT9467 is a switch-mode single cell Li-Ion/Li-Polymer battery charger for
|
||||
portable applications. It integrates a synchronous PWM controller, power
|
||||
MOSFETs, input current sensing and regulation, high-accuracy voltage
|
||||
regulation, and charge termination. The charge current is regulated through
|
||||
integrated sensing resistors.
|
||||
|
||||
The RT9467 also features USB On-The-Go (OTG) support. It also integrates
|
||||
D+/D- pin for USB host/charging port detection.
|
||||
|
||||
Datasheet is available at
|
||||
https://www.richtek.com/assets/product_file/RT9467/DS9467-01.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: richtek,rt9467-charger
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
charge-enable-gpios:
|
||||
description: GPIO is used to turn on and off charging.
|
||||
maxItems: 1
|
||||
|
||||
usb-otg-vbus-regulator:
|
||||
type: object
|
||||
description: OTG boost regulator.
|
||||
unevaluatedProperties: false
|
||||
$ref: /schemas/regulator/regulator.yaml#
|
||||
|
||||
properties:
|
||||
enable-gpios: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- wakeup-source
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@5b {
|
||||
compatible = "richtek,rt9467-charger";
|
||||
reg = <0x5b>;
|
||||
wakeup-source;
|
||||
interrupts-extended = <&gpio_intc 32 IRQ_TYPE_LEVEL_LOW>;
|
||||
charge-enable-gpios = <&gpio26 1 GPIO_ACTIVE_LOW>;
|
||||
|
||||
rt9467_otg_vbus: usb-otg-vbus-regulator {
|
||||
regulator-name = "rt9467-usb-otg-vbus";
|
||||
regulator-min-microvolt = <4425000>;
|
||||
regulator-max-microvolt = <5825000>;
|
||||
regulator-min-microamp = <500000>;
|
||||
regulator-max-microamp = <3000000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/richtek,rt9471.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Richtek RT9471 3A Single Cell Switching Battery charger
|
||||
|
||||
maintainers:
|
||||
- Alina Yu <alina_yu@richtek.com>
|
||||
- ChiYuan Huang <cy_huang@richtek.com>
|
||||
|
||||
description: |
|
||||
RT9471 is a switch-mode single cell Li-Ion/Li-Polymer battery charger for
|
||||
portable applications. It supports USB BC1.2 port detection, current and
|
||||
voltage regulations in both charging and boost mode.
|
||||
|
||||
Datasheet is available at
|
||||
https://www.richtek.com/assets/product_file/RT9471=RT9471D/DS9471D-02.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: richtek,rt9471
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
charge-enable-gpios:
|
||||
description: GPIO used to turn on and off charging.
|
||||
maxItems: 1
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
usb-otg-vbus-regulator:
|
||||
type: object
|
||||
$ref: /schemas/regulator/regulator.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- wakeup-source
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@53 {
|
||||
compatible = "richtek,rt9471";
|
||||
reg = <0x53>;
|
||||
charge-enable-gpios = <&gpio26 1 GPIO_ACTIVE_LOW>;
|
||||
wakeup-source;
|
||||
interrupts-extended = <&gpio_intc 32 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
usb-otg-vbus-regulator {
|
||||
regulator-name = "usb-otg-vbus";
|
||||
regulator-min-microvolt = <4850000>;
|
||||
regulator-max-microvolt = <5300000>;
|
||||
regulator-min-microamp = <500000>;
|
||||
regulator-max-microamp = <1200000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -187,7 +187,7 @@ struct x86_dev_info {
|
|||
/* Generic / shared charger / battery settings */
|
||||
static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" };
|
||||
static const char * const bq24190_psy[] = { "bq24190-charger" };
|
||||
static const char * const bq25890_psy[] = { "bq25890-charger" };
|
||||
static const char * const bq25890_psy[] = { "bq25890-charger-0" };
|
||||
|
||||
static const struct property_entry fg_bq24190_supply_props[] = {
|
||||
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy),
|
||||
|
|
|
@ -141,6 +141,13 @@ config POWER_RESET_OCELOT_RESET
|
|||
help
|
||||
This driver supports restart for Microsemi Ocelot SoC and similar.
|
||||
|
||||
config POWER_RESET_ODROID_GO_ULTRA_POWEROFF
|
||||
bool "Odroid Go Ultra power-off driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on I2C=y && OF
|
||||
help
|
||||
This driver supports Power off for Odroid Go Ultra device.
|
||||
|
||||
config POWER_RESET_OXNAS
|
||||
bool "OXNAS SoC restart driver"
|
||||
depends on ARCH_OXNAS
|
||||
|
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
|
|||
obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o
|
||||
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
|
||||
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
|
||||
obj-$(CONFIG_POWER_RESET_ODROID_GO_ULTRA_POWEROFF) += odroid-go-ultra-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2023 Neil Armstrong <neil.armstrong@linaro.org>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/mfd/rk808.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
/*
|
||||
* The Odroid Go Ultra has 2 PMICs:
|
||||
* - RK818 (manages the battery and USB-C power supply)
|
||||
* - RK817
|
||||
* Both PMICs feeds power to the S922X SoC, so they must be powered-off in sequence.
|
||||
* Vendor does power-off the RK817 first, then the RK818 so here we follow this sequence.
|
||||
*/
|
||||
|
||||
struct odroid_go_ultra_poweroff_data {
|
||||
struct device *dev;
|
||||
struct device *rk817;
|
||||
struct device *rk818;
|
||||
};
|
||||
|
||||
static int odroid_go_ultra_poweroff_prepare(struct sys_off_data *data)
|
||||
{
|
||||
struct odroid_go_ultra_poweroff_data *poweroff_data = data->cb_data;
|
||||
struct regmap *rk817, *rk818;
|
||||
int ret;
|
||||
|
||||
/* RK817 Regmap */
|
||||
rk817 = dev_get_regmap(poweroff_data->rk817, NULL);
|
||||
if (!rk817) {
|
||||
dev_err(poweroff_data->dev, "failed to get rk817 regmap\n");
|
||||
return notifier_from_errno(-EINVAL);
|
||||
}
|
||||
|
||||
/* RK818 Regmap */
|
||||
rk818 = dev_get_regmap(poweroff_data->rk818, NULL);
|
||||
if (!rk818) {
|
||||
dev_err(poweroff_data->dev, "failed to get rk818 regmap\n");
|
||||
return notifier_from_errno(-EINVAL);
|
||||
}
|
||||
|
||||
dev_info(poweroff_data->dev, "Setting PMICs for power off");
|
||||
|
||||
/* RK817 */
|
||||
ret = regmap_update_bits(rk817, RK817_SYS_CFG(3), DEV_OFF, DEV_OFF);
|
||||
if (ret) {
|
||||
dev_err(poweroff_data->dev, "failed to poweroff rk817\n");
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
/* RK818 */
|
||||
ret = regmap_update_bits(rk818, RK818_DEVCTRL_REG, DEV_OFF, DEV_OFF);
|
||||
if (ret) {
|
||||
dev_err(poweroff_data->dev, "failed to poweroff rk818\n");
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void odroid_go_ultra_poweroff_put_pmic_device(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
static int odroid_go_ultra_poweroff_get_pmic_device(struct device *dev, const char *compatible,
|
||||
struct device **pmic)
|
||||
{
|
||||
struct device_node *pmic_node;
|
||||
struct i2c_client *pmic_client;
|
||||
|
||||
pmic_node = of_find_compatible_node(NULL, NULL, compatible);
|
||||
if (!pmic_node)
|
||||
return -ENODEV;
|
||||
|
||||
pmic_client = of_find_i2c_device_by_node(pmic_node);
|
||||
of_node_put(pmic_node);
|
||||
if (!pmic_client)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
*pmic = &pmic_client->dev;
|
||||
|
||||
return devm_add_action_or_reset(dev, odroid_go_ultra_poweroff_put_pmic_device, *pmic);
|
||||
}
|
||||
|
||||
static int odroid_go_ultra_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct odroid_go_ultra_poweroff_data *poweroff_data;
|
||||
int ret;
|
||||
|
||||
poweroff_data = devm_kzalloc(&pdev->dev, sizeof(*poweroff_data), GFP_KERNEL);
|
||||
if (!poweroff_data)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, poweroff_data);
|
||||
|
||||
/* RK818 PMIC Device */
|
||||
ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk818",
|
||||
&poweroff_data->rk818);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get rk818 mfd data\n");
|
||||
|
||||
/* RK817 PMIC Device */
|
||||
ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk817",
|
||||
&poweroff_data->rk817);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get rk817 mfd data\n");
|
||||
|
||||
/* Register as SYS_OFF_MODE_POWER_OFF_PREPARE because regmap_update_bits may sleep */
|
||||
ret = devm_register_sys_off_handler(&pdev->dev,
|
||||
SYS_OFF_MODE_POWER_OFF_PREPARE,
|
||||
SYS_OFF_PRIO_DEFAULT,
|
||||
odroid_go_ultra_poweroff_prepare,
|
||||
poweroff_data);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to register sys-off handler\n");
|
||||
|
||||
dev_info(&pdev->dev, "Registered Power-Off handler\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
static struct platform_device *pdev;
|
||||
|
||||
static struct platform_driver odroid_go_ultra_poweroff_driver = {
|
||||
.driver = {
|
||||
.name = "odroid-go-ultra-poweroff",
|
||||
},
|
||||
.probe = odroid_go_ultra_poweroff_probe,
|
||||
};
|
||||
|
||||
static int __init odroid_go_ultra_poweroff_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Only create when running on the Odroid Go Ultra device */
|
||||
if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))
|
||||
return -ENODEV;
|
||||
|
||||
ret = platform_driver_register(&odroid_go_ultra_poweroff_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pdev = platform_device_register_resndata(NULL, "odroid-go-ultra-poweroff", -1,
|
||||
NULL, 0, NULL, 0);
|
||||
|
||||
if (IS_ERR(pdev)) {
|
||||
platform_driver_unregister(&odroid_go_ultra_poweroff_driver);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit odroid_go_ultra_poweroff_exit(void)
|
||||
{
|
||||
/* Only delete when running on the Odroid Go Ultra device */
|
||||
if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))
|
||||
return;
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
platform_driver_unregister(&odroid_go_ultra_poweroff_driver);
|
||||
}
|
||||
|
||||
module_init(odroid_go_ultra_poweroff_init);
|
||||
module_exit(odroid_go_ultra_poweroff_exit);
|
||||
|
||||
MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
|
||||
MODULE_DESCRIPTION("Odroid Go Ultra poweroff driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -44,6 +44,7 @@ static int syscon_reboot_probe(struct platform_device *pdev)
|
|||
struct syscon_reboot_context *ctx;
|
||||
struct device *dev = &pdev->dev;
|
||||
int mask_err, value_err;
|
||||
int priority;
|
||||
int err;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
|
@ -57,6 +58,9 @@ static int syscon_reboot_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(ctx->map);
|
||||
}
|
||||
|
||||
if (of_property_read_s32(pdev->dev.of_node, "priority", &priority))
|
||||
priority = 192;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -77,7 +81,7 @@ static int syscon_reboot_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ctx->restart_handler.notifier_call = syscon_restart_handle;
|
||||
ctx->restart_handler.priority = 192;
|
||||
ctx->restart_handler.priority = priority;
|
||||
err = register_restart_handler(&ctx->restart_handler);
|
||||
if (err)
|
||||
dev_err(dev, "can't register restart notifier (err=%d)\n", err);
|
||||
|
|
|
@ -765,6 +765,41 @@ config CHARGER_RT9455
|
|||
help
|
||||
Say Y to enable support for Richtek RT9455 battery charger.
|
||||
|
||||
config CHARGER_RT9467
|
||||
tristate "Richtek RT9467 Battery Charger Driver"
|
||||
depends on I2C && GPIOLIB && REGULATOR
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select LINEAR_RANGES
|
||||
help
|
||||
Say Y here to enable RT9467 Battery Charger.
|
||||
RT9467 is a switch-mode single cell Li-Ion/Li-Polymer battery charger
|
||||
for portable applications. It integrates a synchronous PWM controller,
|
||||
power MOSFETs, input current sensing and regulation, high-accuracy
|
||||
voltage regulation, and charge termination. The charge current is
|
||||
regulated through integrated sensing resistors. It also features
|
||||
USB On-The-Go (OTG) support and integrates D+/D- pin for USB
|
||||
host/charging port detection.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called "rt9467-charger".
|
||||
|
||||
config CHARGER_RT9471
|
||||
tristate "Richtek RT9471 battery charger driver"
|
||||
depends on I2C && GPIOLIB && REGULATOR
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select LINEAR_RANGES
|
||||
help
|
||||
This adds support for Richtek RT9471 battery charger. RT9471 is
|
||||
highly-integrated switch mode battery charger which is system power
|
||||
patch manageable device for single cell Li-Ion and Li-polymer battery.
|
||||
It can support BC12 detection on DPDM, and current and voltage
|
||||
regulation on both charging and boost mode.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called rt9471.
|
||||
|
||||
config CHARGER_CROS_USBPD
|
||||
tristate "ChromeOS EC based USBPD charger"
|
||||
depends on CROS_USBPD_NOTIFY
|
||||
|
|
|
@ -54,6 +54,8 @@ obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
|
|||
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
|
||||
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
|
||||
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
|
||||
obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o
|
||||
obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
|
||||
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
|
||||
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
|
||||
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||
|
|
|
@ -2453,7 +2453,7 @@ struct ab8500_fg_sysfs_entry {
|
|||
|
||||
static ssize_t charge_full_show(struct ab8500_fg *di, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", di->bat_cap.max_mah);
|
||||
return sysfs_emit(buf, "%d\n", di->bat_cap.max_mah);
|
||||
}
|
||||
|
||||
static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
|
||||
|
@ -2472,7 +2472,7 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
|
|||
|
||||
static ssize_t charge_now_show(struct ab8500_fg *di, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", di->bat_cap.prev_mah);
|
||||
return sysfs_emit(buf, "%d\n", di->bat_cap.prev_mah);
|
||||
}
|
||||
|
||||
static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf,
|
||||
|
@ -2594,7 +2594,7 @@ static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2644,7 +2644,7 @@ static ssize_t ab8505_powercut_maxtime_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2695,7 +2695,7 @@ static ssize_t ab8505_powercut_restart_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0xF));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2746,7 +2746,7 @@ static ssize_t ab8505_powercut_timer_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2769,7 +2769,7 @@ static ssize_t ab8505_powercut_restart_counter_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF0) >> 4);
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0xF0) >> 4);
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2790,7 +2790,7 @@ static ssize_t ab8505_powercut_read(struct device *dev,
|
|||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x1));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0x1));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2841,7 +2841,7 @@ static ssize_t ab8505_powercut_flag_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x10) >> 4));
|
||||
return sysfs_emit(buf, "%d\n", ((reg_value & 0x10) >> 4));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2864,7 +2864,7 @@ static ssize_t ab8505_powercut_debounce_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7));
|
||||
return sysfs_emit(buf, "%d\n", (reg_value & 0x7));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
@ -2914,7 +2914,7 @@ static ssize_t ab8505_powercut_enable_status_read(struct device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x20) >> 5));
|
||||
return sysfs_emit(buf, "%d\n", ((reg_value & 0x20) >> 5));
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
|
|
@ -1059,7 +1059,7 @@ static ssize_t bq2415x_sysfs_show_status(struct device *dev,
|
|||
ret = bq2415x_exec_command(bq, command);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", ret);
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1098,11 +1098,11 @@ static ssize_t bq2415x_sysfs_show_timer(struct device *dev,
|
|||
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
|
||||
|
||||
if (bq->timer_error)
|
||||
return sprintf(buf, "%s\n", bq->timer_error);
|
||||
return sysfs_emit(buf, "%s\n", bq->timer_error);
|
||||
|
||||
if (bq->autotimer)
|
||||
return sprintf(buf, "auto\n");
|
||||
return sprintf(buf, "off\n");
|
||||
return sysfs_emit(buf, "auto\n");
|
||||
return sysfs_emit(buf, "off\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1175,30 +1175,30 @@ static ssize_t bq2415x_sysfs_show_mode(struct device *dev,
|
|||
ssize_t ret = 0;
|
||||
|
||||
if (bq->automode > 0)
|
||||
ret += sprintf(buf+ret, "auto (");
|
||||
ret += sysfs_emit_at(buf, ret, "auto (");
|
||||
|
||||
switch (bq->mode) {
|
||||
case BQ2415X_MODE_OFF:
|
||||
ret += sprintf(buf+ret, "off");
|
||||
ret += sysfs_emit_at(buf, ret, "off");
|
||||
break;
|
||||
case BQ2415X_MODE_NONE:
|
||||
ret += sprintf(buf+ret, "none");
|
||||
ret += sysfs_emit_at(buf, ret, "none");
|
||||
break;
|
||||
case BQ2415X_MODE_HOST_CHARGER:
|
||||
ret += sprintf(buf+ret, "host");
|
||||
ret += sysfs_emit_at(buf, ret, "host");
|
||||
break;
|
||||
case BQ2415X_MODE_DEDICATED_CHARGER:
|
||||
ret += sprintf(buf+ret, "dedicated");
|
||||
ret += sysfs_emit_at(buf, ret, "dedicated");
|
||||
break;
|
||||
case BQ2415X_MODE_BOOST:
|
||||
ret += sprintf(buf+ret, "boost");
|
||||
ret += sysfs_emit_at(buf, ret, "boost");
|
||||
break;
|
||||
}
|
||||
|
||||
if (bq->automode > 0)
|
||||
ret += sprintf(buf+ret, ")");
|
||||
ret += sysfs_emit_at(buf, ret, ")");
|
||||
|
||||
ret += sprintf(buf+ret, "\n");
|
||||
ret += sysfs_emit_at(buf, ret, "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1215,15 +1215,15 @@ static ssize_t bq2415x_sysfs_show_reported_mode(struct device *dev,
|
|||
|
||||
switch (bq->reported_mode) {
|
||||
case BQ2415X_MODE_OFF:
|
||||
return sprintf(buf, "off\n");
|
||||
return sysfs_emit(buf, "off\n");
|
||||
case BQ2415X_MODE_NONE:
|
||||
return sprintf(buf, "none\n");
|
||||
return sysfs_emit(buf, "none\n");
|
||||
case BQ2415X_MODE_HOST_CHARGER:
|
||||
return sprintf(buf, "host\n");
|
||||
return sysfs_emit(buf, "host\n");
|
||||
case BQ2415X_MODE_DEDICATED_CHARGER:
|
||||
return sprintf(buf, "dedicated\n");
|
||||
return sysfs_emit(buf, "dedicated\n");
|
||||
case BQ2415X_MODE_BOOST:
|
||||
return sprintf(buf, "boost\n");
|
||||
return sysfs_emit(buf, "boost\n");
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -1261,8 +1261,8 @@ static ssize_t bq2415x_sysfs_print_reg(struct bq2415x_device *bq,
|
|||
int ret = bq2415x_i2c_read(bq, reg);
|
||||
|
||||
if (ret < 0)
|
||||
return sprintf(buf, "%#.2x=error %d\n", reg, ret);
|
||||
return sprintf(buf, "%#.2x=%#.2x\n", reg, ret);
|
||||
return sysfs_emit(buf, "%#.2x=error %d\n", reg, ret);
|
||||
return sysfs_emit(buf, "%#.2x=%#.2x\n", reg, ret);
|
||||
}
|
||||
|
||||
/* show all raw values of chip register, format per line: 'register=value' */
|
||||
|
@ -1338,7 +1338,7 @@ static ssize_t bq2415x_sysfs_show_limit(struct device *dev,
|
|||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", ret);
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
/* set *_enable entries */
|
||||
|
@ -1401,7 +1401,7 @@ static ssize_t bq2415x_sysfs_show_enable(struct device *dev,
|
|||
ret = bq2415x_exec_command(bq, command);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", ret);
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(current_limit, S_IWUSR | S_IRUGO,
|
||||
|
|
|
@ -463,7 +463,7 @@ static ssize_t bq24190_sysfs_show(struct device *dev,
|
|||
if (ret)
|
||||
count = ret;
|
||||
else
|
||||
count = scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
|
||||
count = sysfs_emit(buf, "%hhx\n", v);
|
||||
|
||||
pm_runtime_mark_last_busy(bdi->dev);
|
||||
pm_runtime_put_autosuspend(bdi->dev);
|
||||
|
|
|
@ -767,8 +767,7 @@ static ssize_t bq24257_show_ovp_voltage(struct device *dev,
|
|||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct bq24257_device *bq = power_supply_get_drvdata(psy);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
||||
bq24257_vovp_map[bq->init_data.vovp]);
|
||||
return sysfs_emit(buf, "%u\n", bq24257_vovp_map[bq->init_data.vovp]);
|
||||
}
|
||||
|
||||
static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
|
||||
|
@ -778,8 +777,7 @@ static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
|
|||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct bq24257_device *bq = power_supply_get_drvdata(psy);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
||||
bq24257_vindpm_map[bq->init_data.vindpm]);
|
||||
return sysfs_emit(buf, "%u\n", bq24257_vindpm_map[bq->init_data.vindpm]);
|
||||
}
|
||||
|
||||
static ssize_t bq24257_sysfs_show_enable(struct device *dev,
|
||||
|
@ -800,7 +798,7 @@ static ssize_t bq24257_sysfs_show_enable(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t bq24257_sysfs_set_enable(struct device *dev,
|
||||
|
|
|
@ -1563,7 +1563,7 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
|
|||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_ichg(bq,
|
||||
bat_info->constant_charge_current_max_ua);
|
||||
bq->chip_info->bq256xx_def_ichg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1573,7 +1573,7 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
|
|||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_vbatreg(bq,
|
||||
bat_info->constant_charge_voltage_max_uv);
|
||||
bq->chip_info->bq256xx_def_vbatreg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ struct bq25890_init_data {
|
|||
|
||||
struct bq25890_state {
|
||||
u8 online;
|
||||
u8 hiz;
|
||||
u8 chrg_status;
|
||||
u8 chrg_fault;
|
||||
u8 vsys_status;
|
||||
|
@ -107,6 +108,10 @@ struct bq25890_device {
|
|||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct power_supply *charger;
|
||||
struct power_supply *secondary_chrg;
|
||||
struct power_supply_desc desc;
|
||||
char name[28]; /* "bq25890-charger-%d" */
|
||||
int id;
|
||||
|
||||
struct usb_phy *usb_phy;
|
||||
struct notifier_block usb_nb;
|
||||
|
@ -119,7 +124,9 @@ struct bq25890_device {
|
|||
|
||||
bool skip_reset;
|
||||
bool read_back_init_data;
|
||||
bool force_hiz;
|
||||
u32 pump_express_vbus_max;
|
||||
u32 iinlim_percentage;
|
||||
enum bq25890_chip_version chip_version;
|
||||
struct bq25890_init_data init_data;
|
||||
struct bq25890_state state;
|
||||
|
@ -127,6 +134,9 @@ struct bq25890_device {
|
|||
struct mutex lock; /* protect state data */
|
||||
};
|
||||
|
||||
static DEFINE_IDR(bq25890_id);
|
||||
static DEFINE_MUTEX(bq25890_id_mutex);
|
||||
|
||||
static const struct regmap_range bq25890_readonly_reg_ranges[] = {
|
||||
regmap_reg_range(0x0b, 0x0c),
|
||||
regmap_reg_range(0x0e, 0x13),
|
||||
|
@ -454,20 +464,18 @@ static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
|
|||
return bq25890_find_val(ret, TBL_VBUSV);
|
||||
}
|
||||
|
||||
static int bq25890_power_supply_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
static void bq25890_update_state(struct bq25890_device *bq,
|
||||
enum power_supply_property psp,
|
||||
struct bq25890_state *state)
|
||||
{
|
||||
struct bq25890_device *bq = power_supply_get_drvdata(psy);
|
||||
struct bq25890_state state;
|
||||
bool do_adc_conv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&bq->lock);
|
||||
/* update state in case we lost an interrupt */
|
||||
__bq25890_handle_irq(bq);
|
||||
state = bq->state;
|
||||
do_adc_conv = !state.online && bq25890_is_adc_property(psp);
|
||||
*state = bq->state;
|
||||
do_adc_conv = (!state->online || state->hiz) && bq25890_is_adc_property(psp);
|
||||
if (do_adc_conv)
|
||||
bq25890_field_write(bq, F_CONV_START, 1);
|
||||
mutex_unlock(&bq->lock);
|
||||
|
@ -475,10 +483,21 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
|
|||
if (do_adc_conv)
|
||||
regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
|
||||
ret, !ret, 25000, 1000000);
|
||||
}
|
||||
|
||||
static int bq25890_power_supply_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct bq25890_device *bq = power_supply_get_drvdata(psy);
|
||||
struct bq25890_state state;
|
||||
int ret;
|
||||
|
||||
bq25890_update_state(bq, psp, &state);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (!state.online)
|
||||
if (!state.online || state.hiz)
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (state.chrg_status == STATUS_NOT_CHARGING)
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
@ -493,7 +512,8 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
|
|||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
|
||||
if (!state.online || state.hiz ||
|
||||
state.chrg_status == STATUS_NOT_CHARGING ||
|
||||
state.chrg_status == STATUS_TERMINATION_DONE)
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
||||
else if (state.chrg_status == STATUS_PRE_CHARGING)
|
||||
|
@ -513,7 +533,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
|
|||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = state.online;
|
||||
val->intval = state.online && !state.hiz;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
|
@ -667,7 +687,8 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
|
|||
const union power_supply_propval *val)
|
||||
{
|
||||
struct bq25890_device *bq = power_supply_get_drvdata(psy);
|
||||
int maxval;
|
||||
struct bq25890_state state;
|
||||
int maxval, ret;
|
||||
u8 lval;
|
||||
|
||||
switch (psp) {
|
||||
|
@ -682,6 +703,12 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
lval = bq25890_find_idx(val->intval, TBL_IINLIM);
|
||||
return bq25890_field_write(bq, F_IINLIM, lval);
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
|
||||
if (!ret)
|
||||
bq->force_hiz = !val->intval;
|
||||
bq25890_update_state(bq, psp, &state);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -694,12 +721,25 @@ static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are multiple chargers the maximum current the external power-supply
|
||||
* can deliver needs to be divided over the chargers. This is done according
|
||||
* to the bq->iinlim_percentage setting.
|
||||
*/
|
||||
static int bq25890_charger_get_scaled_iinlim_regval(struct bq25890_device *bq,
|
||||
int iinlim_ua)
|
||||
{
|
||||
iinlim_ua = iinlim_ua * bq->iinlim_percentage / 100;
|
||||
return bq25890_find_idx(iinlim_ua, TBL_IINLIM);
|
||||
}
|
||||
|
||||
/* On the BQ25892 try to get charger-type info from our supplier */
|
||||
static void bq25890_charger_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
|
@ -718,7 +758,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
|
|||
|
||||
switch (val.intval) {
|
||||
case POWER_SUPPLY_USB_TYPE_DCP:
|
||||
input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
|
||||
input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 2000000);
|
||||
if (bq->pump_express_vbus_max) {
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&bq->pump_express_work,
|
||||
|
@ -727,11 +767,11 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
|
|||
break;
|
||||
case POWER_SUPPLY_USB_TYPE_CDP:
|
||||
case POWER_SUPPLY_USB_TYPE_ACA:
|
||||
input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
|
||||
input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 1500000);
|
||||
break;
|
||||
case POWER_SUPPLY_USB_TYPE_SDP:
|
||||
default:
|
||||
input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
|
||||
input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 500000);
|
||||
}
|
||||
|
||||
bq25890_field_write(bq, F_IINLIM, input_current_limit);
|
||||
|
@ -748,6 +788,7 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
|
|||
} state_fields[] = {
|
||||
{F_CHG_STAT, &state->chrg_status},
|
||||
{F_PG_STAT, &state->online},
|
||||
{F_EN_HIZ, &state->hiz},
|
||||
{F_VSYS_STAT, &state->vsys_status},
|
||||
{F_BOOST_FAULT, &state->boost_fault},
|
||||
{F_BAT_FAULT, &state->bat_fault},
|
||||
|
@ -763,16 +804,18 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
|
|||
*state_fields[i].data = ret;
|
||||
}
|
||||
|
||||
dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
|
||||
state->chrg_status, state->online, state->vsys_status,
|
||||
state->chrg_fault, state->boost_fault, state->bat_fault,
|
||||
state->ntc_fault);
|
||||
dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
|
||||
state->chrg_status, state->online,
|
||||
state->hiz, state->vsys_status,
|
||||
state->chrg_fault, state->boost_fault,
|
||||
state->bat_fault, state->ntc_fault);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
|
||||
{
|
||||
bool adc_conv_rate, new_adc_conv_rate;
|
||||
struct bq25890_state new_state;
|
||||
int ret;
|
||||
|
||||
|
@ -783,14 +826,23 @@ static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
|
|||
if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (!new_state.online && bq->state.online) { /* power removed */
|
||||
/* disable ADC */
|
||||
ret = bq25890_field_write(bq, F_CONV_RATE, 0);
|
||||
/*
|
||||
* Restore HiZ bit in case it was set by user. The chip does not retain
|
||||
* this bit on cable replug, hence the bit must be reset manually here.
|
||||
*/
|
||||
if (new_state.online && !bq->state.online && bq->force_hiz) {
|
||||
ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
} else if (new_state.online && !bq->state.online) { /* power inserted */
|
||||
/* enable ADC, to have control of charge current/voltage */
|
||||
ret = bq25890_field_write(bq, F_CONV_RATE, 1);
|
||||
new_state.hiz = 1;
|
||||
}
|
||||
|
||||
/* Should period ADC sampling be enabled? */
|
||||
adc_conv_rate = bq->state.online && !bq->state.hiz;
|
||||
new_adc_conv_rate = new_state.online && !new_state.hiz;
|
||||
|
||||
if (new_adc_conv_rate != adc_conv_rate) {
|
||||
ret = bq25890_field_write(bq, F_CONV_RATE, new_adc_conv_rate);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
@ -924,7 +976,7 @@ static int bq25890_hw_init(struct bq25890_device *bq)
|
|||
}
|
||||
|
||||
/* Configure ADC for continuous conversions when charging */
|
||||
ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
|
||||
ret = bq25890_field_write(bq, F_CONV_RATE, bq->state.online && !bq->state.hiz);
|
||||
if (ret < 0) {
|
||||
dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
|
||||
return ret;
|
||||
|
@ -957,7 +1009,6 @@ static char *bq25890_charger_supplied_to[] = {
|
|||
};
|
||||
|
||||
static const struct power_supply_desc bq25890_power_supply_desc = {
|
||||
.name = "bq25890-charger",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = bq25890_power_supply_props,
|
||||
.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
|
||||
|
@ -971,12 +1022,21 @@ static int bq25890_power_supply_init(struct bq25890_device *bq)
|
|||
{
|
||||
struct power_supply_config psy_cfg = { .drv_data = bq, };
|
||||
|
||||
/* Get ID for the device */
|
||||
mutex_lock(&bq25890_id_mutex);
|
||||
bq->id = idr_alloc(&bq25890_id, bq, 0, 0, GFP_KERNEL);
|
||||
mutex_unlock(&bq25890_id_mutex);
|
||||
if (bq->id < 0)
|
||||
return bq->id;
|
||||
|
||||
snprintf(bq->name, sizeof(bq->name), "bq25890-charger-%d", bq->id);
|
||||
bq->desc = bq25890_power_supply_desc;
|
||||
bq->desc.name = bq->name;
|
||||
|
||||
psy_cfg.supplied_to = bq25890_charger_supplied_to;
|
||||
psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
|
||||
|
||||
bq->charger = devm_power_supply_register(bq->dev,
|
||||
&bq25890_power_supply_desc,
|
||||
&psy_cfg);
|
||||
bq->charger = devm_power_supply_register(bq->dev, &bq->desc, &psy_cfg);
|
||||
|
||||
return PTR_ERR_OR_ZERO(bq->charger);
|
||||
}
|
||||
|
@ -996,10 +1056,17 @@ static void bq25890_pump_express_work(struct work_struct *data)
|
|||
{
|
||||
struct bq25890_device *bq =
|
||||
container_of(data, struct bq25890_device, pump_express_work.work);
|
||||
union power_supply_propval value;
|
||||
int voltage, i, ret;
|
||||
|
||||
dev_dbg(bq->dev, "Start to request input voltage increasing\n");
|
||||
|
||||
/* If there is a second charger put in Hi-Z mode */
|
||||
if (bq->secondary_chrg) {
|
||||
value.intval = 0;
|
||||
power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
|
||||
}
|
||||
|
||||
/* Enable current pulse voltage control protocol */
|
||||
ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
|
||||
if (ret < 0)
|
||||
|
@ -1031,6 +1098,11 @@ static void bq25890_pump_express_work(struct work_struct *data)
|
|||
|
||||
bq25890_field_write(bq, F_PUMPX_EN, 0);
|
||||
|
||||
if (bq->secondary_chrg) {
|
||||
value.intval = 1;
|
||||
power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
|
||||
}
|
||||
|
||||
dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
|
||||
voltage);
|
||||
|
||||
|
@ -1077,6 +1149,17 @@ static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
|
|||
static int bq25890_vbus_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct bq25890_device *bq = rdev_get_drvdata(rdev);
|
||||
union power_supply_propval val = {
|
||||
.intval = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* When enabling 5V boost / Vbus output, we need to put the secondary
|
||||
* charger in Hi-Z mode to avoid it trying to charge the secondary
|
||||
* battery from the 5V boost output.
|
||||
*/
|
||||
if (bq->secondary_chrg)
|
||||
power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
|
||||
|
||||
return bq25890_set_otg_cfg(bq, 1);
|
||||
}
|
||||
|
@ -1084,8 +1167,19 @@ static int bq25890_vbus_enable(struct regulator_dev *rdev)
|
|||
static int bq25890_vbus_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct bq25890_device *bq = rdev_get_drvdata(rdev);
|
||||
union power_supply_propval val = {
|
||||
.intval = 1,
|
||||
};
|
||||
int ret;
|
||||
|
||||
return bq25890_set_otg_cfg(bq, 0);
|
||||
ret = bq25890_set_otg_cfg(bq, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bq->secondary_chrg)
|
||||
power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
|
||||
|
@ -1296,11 +1390,31 @@ static int bq25890_fw_probe(struct bq25890_device *bq)
|
|||
{
|
||||
int ret;
|
||||
struct bq25890_init_data *init = &bq->init_data;
|
||||
const char *str;
|
||||
u32 val;
|
||||
|
||||
ret = device_property_read_string(bq->dev, "linux,secondary-charger-name", &str);
|
||||
if (ret == 0) {
|
||||
bq->secondary_chrg = power_supply_get_by_name(str);
|
||||
if (!bq->secondary_chrg)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* Optional, left at 0 if property is not present */
|
||||
device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
|
||||
&bq->pump_express_vbus_max);
|
||||
|
||||
ret = device_property_read_u32(bq->dev, "linux,iinlim-percentage", &val);
|
||||
if (ret == 0) {
|
||||
if (val > 100) {
|
||||
dev_err(bq->dev, "Error linux,iinlim-percentage %u > 100\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
bq->iinlim_percentage = val;
|
||||
} else {
|
||||
bq->iinlim_percentage = 100;
|
||||
}
|
||||
|
||||
bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
|
||||
bq->read_back_init_data = device_property_read_bool(bq->dev,
|
||||
"linux,read-back-settings");
|
||||
|
@ -1322,6 +1436,12 @@ static void bq25890_non_devm_cleanup(void *data)
|
|||
struct bq25890_device *bq = data;
|
||||
|
||||
cancel_delayed_work_sync(&bq->pump_express_work);
|
||||
|
||||
if (bq->id >= 0) {
|
||||
mutex_lock(&bq25890_id_mutex);
|
||||
idr_remove(&bq25890_id, bq->id);
|
||||
mutex_unlock(&bq25890_id_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int bq25890_probe(struct i2c_client *client)
|
||||
|
@ -1336,6 +1456,7 @@ static int bq25890_probe(struct i2c_client *client)
|
|||
|
||||
bq->client = client;
|
||||
bq->dev = dev;
|
||||
bq->id = -1;
|
||||
|
||||
mutex_init(&bq->lock);
|
||||
INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
|
||||
|
|
|
@ -1917,10 +1917,10 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
|
|||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
if (di->cache.flags & BQ27000_FLAG_FC)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDV1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDVF)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDV1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||
} else if (di->opts & BQ27Z561_O_BITS) {
|
||||
|
@ -1933,10 +1933,10 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
|
|||
} else {
|
||||
if (di->cache.flags & BQ27XXX_FLAG_FC)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||
else if (di->cache.flags & BQ27XXX_FLAG_SOC1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else if (di->cache.flags & BQ27XXX_FLAG_SOCF)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
|
||||
else if (di->cache.flags & BQ27XXX_FLAG_SOC1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||
}
|
||||
|
|
|
@ -1075,7 +1075,7 @@ static ssize_t charger_name_show(struct device *dev,
|
|||
struct charger_regulator *charger
|
||||
= container_of(attr, struct charger_regulator, attr_name);
|
||||
|
||||
return sprintf(buf, "%s\n", charger->regulator_name);
|
||||
return sysfs_emit(buf, "%s\n", charger->regulator_name);
|
||||
}
|
||||
|
||||
static ssize_t charger_state_show(struct device *dev,
|
||||
|
@ -1088,7 +1088,7 @@ static ssize_t charger_state_show(struct device *dev,
|
|||
if (!charger->externally_control)
|
||||
state = regulator_is_enabled(charger->consumer);
|
||||
|
||||
return sprintf(buf, "%s\n", state ? "enabled" : "disabled");
|
||||
return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
static ssize_t charger_externally_control_show(struct device *dev,
|
||||
|
@ -1097,7 +1097,7 @@ static ssize_t charger_externally_control_show(struct device *dev,
|
|||
struct charger_regulator *charger = container_of(attr,
|
||||
struct charger_regulator, attr_externally_control);
|
||||
|
||||
return sprintf(buf, "%d\n", charger->externally_control);
|
||||
return sysfs_emit(buf, "%d\n", charger->externally_control);
|
||||
}
|
||||
|
||||
static ssize_t charger_externally_control_store(struct device *dev,
|
||||
|
|
|
@ -404,7 +404,7 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
|
|||
goto err_psy_reg_bu;
|
||||
}
|
||||
|
||||
ret = request_irq(gpio_to_irq(COLLIE_GPIO_CO),
|
||||
ret = request_irq(gpiod_to_irq(collie_bat_main.gpio_full),
|
||||
collie_bat_gpio_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"main full", &collie_bat_main);
|
||||
|
@ -440,7 +440,7 @@ err_put_gpio_full:
|
|||
|
||||
static void collie_bat_remove(struct ucb1x00_dev *dev)
|
||||
{
|
||||
free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
|
||||
free_irq(gpiod_to_irq(collie_bat_main.gpio_full), &collie_bat_main);
|
||||
power_supply_unregister(collie_bat_bu.psy);
|
||||
power_supply_unregister(collie_bat_main.psy);
|
||||
|
||||
|
|
|
@ -466,10 +466,8 @@ static int da9150_charger_register_irq(struct platform_device *pdev,
|
|||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, irq_name);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT, irq_name,
|
||||
charger);
|
||||
|
@ -482,15 +480,12 @@ static int da9150_charger_register_irq(struct platform_device *pdev,
|
|||
static void da9150_charger_unregister_irq(struct platform_device *pdev,
|
||||
const char *irq_name)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct da9150_charger *charger = platform_get_drvdata(pdev);
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, irq_name);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
free_irq(irq, charger);
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ static ssize_t ds2780_get_pmod_enabled(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
return sysfs_emit(buf, "%d\n",
|
||||
!!(control_reg & DS2780_CONTROL_REG_PMOD));
|
||||
}
|
||||
|
||||
|
@ -507,7 +507,7 @@ static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sprintf(buf, "%d\n", sense_resistor);
|
||||
ret = sysfs_emit(buf, "%d\n", sense_resistor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -545,7 +545,7 @@ static ssize_t ds2780_get_rsgain_setting(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", rsgain);
|
||||
return sysfs_emit(buf, "%d\n", rsgain);
|
||||
}
|
||||
|
||||
static ssize_t ds2780_set_rsgain_setting(struct device *dev,
|
||||
|
@ -588,7 +588,7 @@ static ssize_t ds2780_get_pio_pin(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sprintf(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
|
||||
ret = sysfs_emit(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -456,7 +456,7 @@ static ssize_t ds2781_get_pmod_enabled(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
return sysfs_emit(buf, "%d\n",
|
||||
!!(control_reg & DS2781_CONTROL_PMOD));
|
||||
}
|
||||
|
||||
|
@ -509,7 +509,7 @@ static ssize_t ds2781_get_sense_resistor_value(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sprintf(buf, "%d\n", sense_resistor);
|
||||
ret = sysfs_emit(buf, "%d\n", sense_resistor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -547,7 +547,7 @@ static ssize_t ds2781_get_rsgain_setting(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", rsgain);
|
||||
return sysfs_emit(buf, "%d\n", rsgain);
|
||||
}
|
||||
|
||||
static ssize_t ds2781_set_rsgain_setting(struct device *dev,
|
||||
|
@ -590,7 +590,7 @@ static ssize_t ds2781_get_pio_pin(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sprintf(buf, "%d\n", sfr & DS2781_SFR_PIOSC);
|
||||
ret = sysfs_emit(buf, "%d\n", sfr & DS2781_SFR_PIOSC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -602,7 +602,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev,
|
|||
lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
|
||||
state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]);
|
||||
return sysfs_emit(buf, "%s\n", desc[state]);
|
||||
}
|
||||
|
||||
static ssize_t lp8788_show_eoc_time(struct device *dev,
|
||||
|
@ -618,8 +618,7 @@ static ssize_t lp8788_show_eoc_time(struct device *dev,
|
|||
lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
|
||||
val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n",
|
||||
stime[val]);
|
||||
return sysfs_emit(buf, "End Of Charge Time: %s\n", stime[val]);
|
||||
}
|
||||
|
||||
static ssize_t lp8788_show_eoc_level(struct device *dev,
|
||||
|
@ -642,7 +641,7 @@ static ssize_t lp8788_show_eoc_level(struct device *dev,
|
|||
val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;
|
||||
level = mode ? abs_level[val] : relative_level[val];
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level);
|
||||
return sysfs_emit(buf, "End Of Charge Level: %s\n", level);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
|
||||
|
|
|
@ -525,7 +525,7 @@ static ssize_t charge_status_show(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", result);
|
||||
return sysfs_emit(buf, "%s\n", result);
|
||||
}
|
||||
static DEVICE_ATTR_RO(charge_status);
|
||||
|
||||
|
@ -541,7 +541,7 @@ static ssize_t vbat_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val.intval);
|
||||
return sysfs_emit(buf, "%d\n", val.intval);
|
||||
}
|
||||
static DEVICE_ATTR_RO(vbat);
|
||||
|
||||
|
@ -557,7 +557,7 @@ static ssize_t vbat_avg_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val.intval);
|
||||
return sysfs_emit(buf, "%d\n", val.intval);
|
||||
}
|
||||
static DEVICE_ATTR_RO(vbat_avg);
|
||||
|
||||
|
@ -573,7 +573,7 @@ static ssize_t ibat_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val.intval);
|
||||
return sysfs_emit(buf, "%d\n", val.intval);
|
||||
}
|
||||
static DEVICE_ATTR_RO(ibat);
|
||||
|
||||
|
@ -589,7 +589,7 @@ static ssize_t force_telemetry_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u\n", regval & BIT(2) ? 1 : 0);
|
||||
return sysfs_emit(buf, "%u\n", regval & BIT(2) ? 1 : 0);
|
||||
}
|
||||
|
||||
static ssize_t force_telemetry_store(struct device *dev,
|
||||
|
@ -628,7 +628,7 @@ static ssize_t arm_ship_mode_show(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -532,7 +532,7 @@ static ssize_t show_fast_charge_timer(struct device *dev,
|
|||
break;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
|
||||
static ssize_t store_fast_charge_timer(struct device *dev,
|
||||
|
|
|
@ -384,7 +384,7 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl)
|
|||
}
|
||||
|
||||
if (!info->ManufacturerName[0])
|
||||
strncpy(info->ManufacturerName, DEF_MFG_NAME,
|
||||
strscpy(info->ManufacturerName, DEF_MFG_NAME,
|
||||
2 * MAX1721X_REG_MFG_NUMB);
|
||||
|
||||
if (get_string(info, MAX1721X_REG_DEV_STR,
|
||||
|
@ -403,15 +403,15 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl)
|
|||
|
||||
switch (dev_name & MAX172XX_DEV_MASK) {
|
||||
case MAX172X1_DEV:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
|
||||
strscpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
break;
|
||||
case MAX172X5_DEV:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
|
||||
strscpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
break;
|
||||
default:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
|
||||
strscpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ static int max77650_charger_enable(struct max77650_charger_data *chg)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static int max77650_charger_disable(struct max77650_charger_data *chg)
|
||||
static void max77650_charger_disable(struct max77650_charger_data *chg)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
@ -151,8 +151,6 @@ static int max77650_charger_disable(struct max77650_charger_data *chg)
|
|||
MAX77650_CHARGER_DISABLED);
|
||||
if (rv)
|
||||
dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static irqreturn_t max77650_charger_check_status(int irq, void *data)
|
||||
|
@ -351,7 +349,9 @@ static int max77650_charger_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct max77650_charger_data *chg = platform_get_drvdata(pdev);
|
||||
|
||||
return max77650_charger_disable(chg);
|
||||
max77650_charger_disable(chg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id max77650_charger_of_match[] = {
|
||||
|
|
|
@ -296,7 +296,7 @@ static ssize_t fast_charge_timer_show(struct device *dev,
|
|||
break;
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
|
||||
static int max77693_set_fast_charge_timer(struct max77693_charger *chg,
|
||||
|
@ -357,7 +357,7 @@ static ssize_t top_off_threshold_current_show(struct device *dev,
|
|||
else
|
||||
val = data * 50000;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
|
||||
static int max77693_set_top_off_threshold_current(struct max77693_charger *chg,
|
||||
|
@ -405,7 +405,7 @@ static ssize_t top_off_timer_show(struct device *dev,
|
|||
|
||||
val = data * 10;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||
return sysfs_emit(buf, "%u\n", val);
|
||||
}
|
||||
|
||||
static int max77693_set_top_off_timer(struct max77693_charger *chg,
|
||||
|
|
|
@ -519,7 +519,7 @@ static ssize_t batt_impedance_compensation_show(struct device *dev,
|
|||
return ret;
|
||||
|
||||
rval = (rval >> 4) * 10;
|
||||
return sprintf(buf, "%d mohm\n", rval);
|
||||
return sysfs_emit(buf, "%d mohm\n", rval);
|
||||
}
|
||||
|
||||
static ssize_t batt_impedance_compensation_store(struct device *dev,
|
||||
|
|
|
@ -568,7 +568,7 @@ static ssize_t olpc_bat_error_read(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", ec_byte);
|
||||
return sysfs_emit(buf, "%d\n", ec_byte);
|
||||
}
|
||||
|
||||
static struct device_attribute olpc_bat_error = {
|
||||
|
|
|
@ -153,7 +153,7 @@ show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
|
||||
u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
|
||||
|
||||
return sprintf(buf, "%d\n", chgmod);
|
||||
return sysfs_emit(buf, "%d\n", chgmod);
|
||||
}
|
||||
static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
|
||||
|
||||
|
@ -174,7 +174,7 @@ show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
else
|
||||
ma = 0;
|
||||
|
||||
return sprintf(buf, "%u\n", ma);
|
||||
return sysfs_emit(buf, "%u\n", ma);
|
||||
}
|
||||
|
||||
static ssize_t set_usblim(struct device *dev,
|
||||
|
@ -207,7 +207,7 @@ show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8;
|
||||
|
||||
return sprintf(buf, "%u\n", ma);
|
||||
return sysfs_emit(buf, "%u\n", ma);
|
||||
}
|
||||
|
||||
static ssize_t set_chglim(struct device *dev,
|
||||
|
|
|
@ -1186,83 +1186,6 @@ static void psy_unregister_thermal(struct power_supply *psy)
|
|||
thermal_zone_device_unregister(psy->tzd);
|
||||
}
|
||||
|
||||
/* thermal cooling device callbacks */
|
||||
static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
ret = power_supply_get_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*state = val.intval;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ps_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
ret = power_supply_get_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*state = val.intval;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
val.intval = state;
|
||||
ret = psy->desc->set_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct thermal_cooling_device_ops psy_tcd_ops = {
|
||||
.get_max_state = ps_get_max_charge_cntl_limit,
|
||||
.get_cur_state = ps_get_cur_charge_cntl_limit,
|
||||
.set_cur_state = ps_set_cur_charge_cntl_limit,
|
||||
};
|
||||
|
||||
static int psy_register_cooler(struct power_supply *psy)
|
||||
{
|
||||
/* Register for cooling device if psy can control charging */
|
||||
if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT)) {
|
||||
psy->tcd = thermal_cooling_device_register(
|
||||
(char *)psy->desc->name,
|
||||
psy, &psy_tcd_ops);
|
||||
return PTR_ERR_OR_ZERO(psy->tcd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psy_unregister_cooler(struct power_supply *psy)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(psy->tcd))
|
||||
return;
|
||||
thermal_cooling_device_unregister(psy->tcd);
|
||||
}
|
||||
#else
|
||||
static int psy_register_thermal(struct power_supply *psy)
|
||||
{
|
||||
|
@ -1272,15 +1195,6 @@ static int psy_register_thermal(struct power_supply *psy)
|
|||
static void psy_unregister_thermal(struct power_supply *psy)
|
||||
{
|
||||
}
|
||||
|
||||
static int psy_register_cooler(struct power_supply *psy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psy_unregister_cooler(struct power_supply *psy)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct power_supply *__must_check
|
||||
|
@ -1354,10 +1268,6 @@ __power_supply_register(struct device *parent,
|
|||
if (rc)
|
||||
goto register_thermal_failed;
|
||||
|
||||
rc = psy_register_cooler(psy);
|
||||
if (rc)
|
||||
goto register_cooler_failed;
|
||||
|
||||
rc = power_supply_create_triggers(psy);
|
||||
if (rc)
|
||||
goto create_triggers_failed;
|
||||
|
@ -1387,8 +1297,6 @@ __power_supply_register(struct device *parent,
|
|||
add_hwmon_sysfs_failed:
|
||||
power_supply_remove_triggers(psy);
|
||||
create_triggers_failed:
|
||||
psy_unregister_cooler(psy);
|
||||
register_cooler_failed:
|
||||
psy_unregister_thermal(psy);
|
||||
register_thermal_failed:
|
||||
wakeup_init_failed:
|
||||
|
@ -1540,7 +1448,6 @@ void power_supply_unregister(struct power_supply *psy)
|
|||
sysfs_remove_link(&psy->dev.kobj, "powers");
|
||||
power_supply_remove_hwmon_sysfs(psy);
|
||||
power_supply_remove_triggers(psy);
|
||||
psy_unregister_cooler(psy);
|
||||
psy_unregister_thermal(psy);
|
||||
device_init_wakeup(&psy->dev, false);
|
||||
device_unregister(&psy->dev);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include "power_supply.h"
|
||||
|
||||
|
|
|
@ -249,11 +249,11 @@ static ssize_t power_supply_show_usb_type(struct device *dev,
|
|||
usb_type = desc->usb_types[i];
|
||||
|
||||
if (value->intval == usb_type) {
|
||||
count += sprintf(buf + count, "[%s] ",
|
||||
count += sysfs_emit_at(buf, count, "[%s] ",
|
||||
POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
|
||||
match = true;
|
||||
} else {
|
||||
count += sprintf(buf + count, "%s ",
|
||||
count += sysfs_emit_at(buf, count, "%s ",
|
||||
POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ static ssize_t power_supply_show_property(struct device *dev,
|
|||
|
||||
if (ps_attr->text_values_len > 0 &&
|
||||
value.intval < ps_attr->text_values_len && value.intval >= 0) {
|
||||
return sprintf(buf, "%s\n", ps_attr->text_values[value.intval]);
|
||||
return sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]);
|
||||
}
|
||||
|
||||
switch (psp) {
|
||||
|
@ -306,10 +306,10 @@ static ssize_t power_supply_show_property(struct device *dev,
|
|||
&value, buf);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
ret = sprintf(buf, "%s\n", value.strval);
|
||||
ret = sysfs_emit(buf, "%s\n", value.strval);
|
||||
break;
|
||||
default:
|
||||
ret = sprintf(buf, "%d\n", value.intval);
|
||||
ret = sysfs_emit(buf, "%d\n", value.intval);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,930 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2022 Richtek Technology Corp.
|
||||
*
|
||||
* Authors: Alina Yu <alina_yu@richtek.com>
|
||||
* ChiYuan Huang <cy_huang@richtek.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/linear_range.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define RT9471_REG_OTGCFG 0x00
|
||||
#define RT9471_REG_TOP 0x01
|
||||
#define RT9471_REG_FUNC 0x02
|
||||
#define RT9471_REG_IBUS 0x03
|
||||
#define RT9471_REG_VBUS 0x04
|
||||
#define RT9471_REG_PRECHG 0x05
|
||||
#define RT9471_REG_VCHG 0x07
|
||||
#define RT9471_REG_ICHG 0x08
|
||||
#define RT9471_REG_CHGTMR 0x09
|
||||
#define RT9471_REG_EOC 0x0A
|
||||
#define RT9471_REG_INFO 0x0B
|
||||
#define RT9471_REG_JEITA 0x0C
|
||||
#define RT9471_REG_PUMP_EXP 0x0D
|
||||
#define RT9471_REG_DPDMDET 0x0E
|
||||
#define RT9471_REG_ICSTAT 0x0F
|
||||
#define RT9471_REG_STAT0 0x10
|
||||
#define RT9471_REG_STAT1 0x11
|
||||
#define RT9471_REG_STAT2 0x12
|
||||
#define RT9471_REG_IRQ0 0x20
|
||||
#define RT9471_REG_MASK0 0x30
|
||||
|
||||
#define RT9471_OTGCV_MASK GENMASK(7, 6)
|
||||
#define RT9471_OTGCC_MASK BIT(0)
|
||||
#define RT9471_OTGEN_MASK BIT(1)
|
||||
#define RT9471_CHGFAULT_MASK GENMASK(4, 1)
|
||||
|
||||
#define RT9471_NUM_IRQ_REGS 4
|
||||
#define RT9471_OTGCV_MINUV 4850000
|
||||
#define RT9471_OTGCV_STEPUV 150000
|
||||
#define RT9471_NUM_VOTG 4
|
||||
#define RT9471_VCHG_MAXUV 4700000
|
||||
#define RT9471_ICHG_MAXUA 3150000
|
||||
|
||||
/* Device ID */
|
||||
#define RT9470_DEVID 0x09
|
||||
#define RT9470D_DEVID 0x0A
|
||||
#define RT9471_DEVID 0x0D
|
||||
#define RT9471D_DEVID 0x0E
|
||||
|
||||
/* IRQ number */
|
||||
#define RT9471_IRQ_BC12_DONE 0
|
||||
#define RT9471_IRQ_DETACH 1
|
||||
#define RT9471_IRQ_RECHG 2
|
||||
#define RT9471_IRQ_CHG_DONE 3
|
||||
#define RT9471_IRQ_BG_CHG 4
|
||||
#define RT9471_IRQ_IE0C 5
|
||||
#define RT9471_IRQ_CHG_RDY 6
|
||||
#define RT9471_IRQ_VBUS_GD 7
|
||||
#define RT9471_IRQ_CHG_BATOV 9
|
||||
#define RT9471_IRQ_CHG_SYSOV 10
|
||||
#define RT9471_IRQ_CHG_TOUT 11
|
||||
#define RT9471_IRQ_CHG_BUSUV 12
|
||||
#define RT9471_IRQ_CHG_THREG 13
|
||||
#define RT9471_IRQ_CHG_AICR 14
|
||||
#define RT9471_IRQ_CHG_MIVR 15
|
||||
#define RT9471_IRQ_SYS_SHORT 16
|
||||
#define RT9471_IRQ_SYS_MIN 17
|
||||
#define RT9471_IRQ_AICC_DONE 18
|
||||
#define RT9471_IRQ_PE_DONE 19
|
||||
#define RT9471_IRQ_JEITA_COLD 20
|
||||
#define RT9471_IRQ_JEITA_COOL 21
|
||||
#define RT9471_IRQ_JEITA_WARM 22
|
||||
#define RT9471_IRQ_JEITA_HOT 23
|
||||
#define RT9471_IRQ_OTG_FAULT 24
|
||||
#define RT9471_IRQ_OTG_LBP 25
|
||||
#define RT9471_IRQ_OTG_CC 26
|
||||
#define RT9471_IRQ_WDT 29
|
||||
#define RT9471_IRQ_VAC_OV 30
|
||||
#define RT9471_IRQ_OTP 31
|
||||
|
||||
enum rt9471_fields {
|
||||
F_WDT = 0,
|
||||
F_WDT_RST,
|
||||
F_CHG_EN,
|
||||
F_HZ,
|
||||
F_BATFET_DIS,
|
||||
F_AICR,
|
||||
F_AICC_EN,
|
||||
F_MIVR,
|
||||
F_IPRE_CHG,
|
||||
F_VPRE_CHG,
|
||||
F_VBAT_REG,
|
||||
F_ICHG_REG,
|
||||
F_EOC_RST,
|
||||
F_TE,
|
||||
F_IEOC_CHG,
|
||||
F_DEVICE_ID,
|
||||
F_REG_RST,
|
||||
F_BC12_EN,
|
||||
F_IC_STAT,
|
||||
F_PORT_STAT,
|
||||
F_ST_CHG_DONE,
|
||||
F_ST_CHG_RDY,
|
||||
F_ST_VBUS_GD,
|
||||
F_MAX_FIELDS
|
||||
};
|
||||
|
||||
enum rt9471_ranges {
|
||||
RT9471_RANGE_AICR = 0,
|
||||
RT9471_RANGE_MIVR,
|
||||
RT9471_RANGE_IPRE,
|
||||
RT9471_RANGE_VCHG,
|
||||
RT9471_RANGE_ICHG,
|
||||
RT9471_RANGE_IEOC,
|
||||
RT9471_MAX_RANGES
|
||||
};
|
||||
|
||||
enum {
|
||||
RT9471_PORTSTAT_APPLE_10W = 8,
|
||||
RT9471_PORTSTAT_SAMSUNG_10W,
|
||||
RT9471_PORTSTAT_APPLE_5W,
|
||||
RT9471_PORTSTAT_APPLE_12W,
|
||||
RT9471_PORTSTAT_NSTD,
|
||||
RT9471_PORTSTAT_SDP,
|
||||
RT9471_PORTSTAT_CDP,
|
||||
RT9471_PORTSTAT_DCP,
|
||||
};
|
||||
|
||||
struct rt9471_chip {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *rm_fields[F_MAX_FIELDS];
|
||||
struct regmap_irq_chip_data *irq_chip_data;
|
||||
struct regulator_dev *otg_rdev;
|
||||
struct power_supply *psy;
|
||||
struct power_supply_desc psy_desc;
|
||||
struct mutex var_lock;
|
||||
enum power_supply_usb_type psy_usb_type;
|
||||
int psy_usb_curr;
|
||||
};
|
||||
|
||||
static const struct reg_field rt9471_reg_fields[F_MAX_FIELDS] = {
|
||||
[F_WDT] = REG_FIELD(RT9471_REG_TOP, 0, 0),
|
||||
[F_WDT_RST] = REG_FIELD(RT9471_REG_TOP, 1, 1),
|
||||
[F_CHG_EN] = REG_FIELD(RT9471_REG_FUNC, 0, 0),
|
||||
[F_HZ] = REG_FIELD(RT9471_REG_FUNC, 5, 5),
|
||||
[F_BATFET_DIS] = REG_FIELD(RT9471_REG_FUNC, 7, 7),
|
||||
[F_AICR] = REG_FIELD(RT9471_REG_IBUS, 0, 5),
|
||||
[F_AICC_EN] = REG_FIELD(RT9471_REG_IBUS, 7, 7),
|
||||
[F_MIVR] = REG_FIELD(RT9471_REG_VBUS, 0, 3),
|
||||
[F_IPRE_CHG] = REG_FIELD(RT9471_REG_PRECHG, 0, 3),
|
||||
[F_VPRE_CHG] = REG_FIELD(RT9471_REG_PRECHG, 4, 6),
|
||||
[F_VBAT_REG] = REG_FIELD(RT9471_REG_VCHG, 0, 6),
|
||||
[F_ICHG_REG] = REG_FIELD(RT9471_REG_ICHG, 0, 5),
|
||||
[F_EOC_RST] = REG_FIELD(RT9471_REG_EOC, 0, 0),
|
||||
[F_TE] = REG_FIELD(RT9471_REG_EOC, 1, 1),
|
||||
[F_IEOC_CHG] = REG_FIELD(RT9471_REG_EOC, 4, 7),
|
||||
[F_DEVICE_ID] = REG_FIELD(RT9471_REG_INFO, 3, 6),
|
||||
[F_REG_RST] = REG_FIELD(RT9471_REG_INFO, 7, 7),
|
||||
[F_BC12_EN] = REG_FIELD(RT9471_REG_DPDMDET, 7, 7),
|
||||
[F_IC_STAT] = REG_FIELD(RT9471_REG_ICSTAT, 0, 3),
|
||||
[F_PORT_STAT] = REG_FIELD(RT9471_REG_ICSTAT, 4, 7),
|
||||
[F_ST_CHG_DONE] = REG_FIELD(RT9471_REG_STAT0, 3, 3),
|
||||
[F_ST_CHG_RDY] = REG_FIELD(RT9471_REG_STAT0, 6, 6),
|
||||
[F_ST_VBUS_GD] = REG_FIELD(RT9471_REG_STAT0, 7, 7),
|
||||
};
|
||||
|
||||
static const struct linear_range rt9471_chg_ranges[RT9471_MAX_RANGES] = {
|
||||
[RT9471_RANGE_AICR] = { .min = 50000, .min_sel = 1, .max_sel = 63, .step = 50000 },
|
||||
[RT9471_RANGE_MIVR] = { .min = 3900000, .min_sel = 0, .max_sel = 15, .step = 100000 },
|
||||
[RT9471_RANGE_IPRE] = { .min = 50000, .min_sel = 0, .max_sel = 15, .step = 50000 },
|
||||
[RT9471_RANGE_VCHG] = { .min = 3900000, .min_sel = 0, .max_sel = 80, .step = 10000 },
|
||||
[RT9471_RANGE_ICHG] = { .min = 0, .min_sel = 0, .max_sel = 63, .step = 50000 },
|
||||
[RT9471_RANGE_IEOC] = { .min = 50000, .min_sel = 0, .max_sel = 15, .step = 50000 },
|
||||
};
|
||||
|
||||
static int rt9471_set_value_by_field_range(struct rt9471_chip *chip,
|
||||
enum rt9471_fields field,
|
||||
enum rt9471_ranges range, int val)
|
||||
{
|
||||
unsigned int sel;
|
||||
|
||||
if (val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
linear_range_get_selector_within(rt9471_chg_ranges + range, val, &sel);
|
||||
|
||||
return regmap_field_write(chip->rm_fields[field], sel);
|
||||
}
|
||||
|
||||
|
||||
static int rt9471_get_value_by_field_range(struct rt9471_chip *chip,
|
||||
enum rt9471_fields field,
|
||||
enum rt9471_ranges range, int *val)
|
||||
{
|
||||
unsigned int sel, rvalue;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[field], &sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = linear_range_get_value(rt9471_chg_ranges + range, sel, &rvalue);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = rvalue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt9471_set_ieoc(struct rt9471_chip *chip, int microamp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (microamp == 0)
|
||||
return regmap_field_write(chip->rm_fields[F_TE], 0);
|
||||
|
||||
ret = rt9471_set_value_by_field_range(chip, F_IEOC_CHG, RT9471_RANGE_IEOC, microamp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* After applying the new IEOC value, enable charge termination */
|
||||
return regmap_field_write(chip->rm_fields[F_TE], 1);
|
||||
}
|
||||
|
||||
static int rt9471_get_ieoc(struct rt9471_chip *chip, int *microamp)
|
||||
{
|
||||
unsigned int chg_term_enable;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_TE], &chg_term_enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!chg_term_enable) {
|
||||
*microamp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rt9471_get_value_by_field_range(chip, F_IEOC_CHG, RT9471_RANGE_IEOC, microamp);
|
||||
}
|
||||
|
||||
static int rt9471_get_status(struct rt9471_chip *chip, int *status)
|
||||
{
|
||||
unsigned int chg_ready, chg_done, fault_stat;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_ST_CHG_RDY], &chg_ready);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_ST_CHG_DONE], &chg_done);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(chip->regmap, RT9471_REG_STAT1, &fault_stat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fault_stat &= RT9471_CHGFAULT_MASK;
|
||||
|
||||
if (chg_ready && chg_done)
|
||||
*status = POWER_SUPPLY_STATUS_FULL;
|
||||
else if (chg_ready && fault_stat)
|
||||
*status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
else if (chg_ready && !fault_stat)
|
||||
*status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else
|
||||
*status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt9471_get_vbus_good(struct rt9471_chip *chip, int *stat)
|
||||
{
|
||||
unsigned int vbus_gd;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_ST_VBUS_GD], &vbus_gd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*stat = vbus_gd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt9471_get_usb_type(struct rt9471_chip *chip, int *usb_type)
|
||||
{
|
||||
mutex_lock(&chip->var_lock);
|
||||
*usb_type = chip->psy_usb_type;
|
||||
mutex_unlock(&chip->var_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt9471_get_usb_type_current(struct rt9471_chip *chip,
|
||||
int *microamp)
|
||||
{
|
||||
mutex_lock(&chip->var_lock);
|
||||
*microamp = chip->psy_usb_curr;
|
||||
mutex_unlock(&chip->var_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property rt9471_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
|
||||
POWER_SUPPLY_PROP_USB_TYPE,
|
||||
POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
|
||||
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_usb_type rt9471_charger_usb_types[] = {
|
||||
POWER_SUPPLY_USB_TYPE_UNKNOWN,
|
||||
POWER_SUPPLY_USB_TYPE_SDP,
|
||||
POWER_SUPPLY_USB_TYPE_DCP,
|
||||
POWER_SUPPLY_USB_TYPE_CDP,
|
||||
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID,
|
||||
};
|
||||
|
||||
static int rt9471_charger_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
|
||||
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int rt9471_charger_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct rt9471_chip *chip = power_supply_get_drvdata(psy);
|
||||
int value = val->intval;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
return regmap_field_write(chip->rm_fields[F_CHG_EN], !!value);
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
return regmap_field_write(chip->rm_fields[F_HZ], !value);
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
return rt9471_set_value_by_field_range(chip, F_ICHG_REG, RT9471_RANGE_ICHG, value);
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
return rt9471_set_value_by_field_range(chip, F_VBAT_REG, RT9471_RANGE_VCHG, value);
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
return rt9471_set_value_by_field_range(chip, F_AICR, RT9471_RANGE_AICR, value);
|
||||
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||
return rt9471_set_value_by_field_range(chip, F_MIVR, RT9471_RANGE_MIVR, value);
|
||||
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
|
||||
return rt9471_set_value_by_field_range(chip, F_IPRE_CHG, RT9471_RANGE_IPRE, value);
|
||||
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
||||
return rt9471_set_ieoc(chip, val->intval);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const rt9471_manufacturer = "Richtek Technology Corp.";
|
||||
static const char * const rt9471_model = "RT9471";
|
||||
|
||||
static int rt9471_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct rt9471_chip *chip = power_supply_get_drvdata(psy);
|
||||
int *pvalue = &val->intval;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
return rt9471_get_status(chip, pvalue);
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
return rt9471_get_vbus_good(chip, pvalue);
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
return rt9471_get_usb_type_current(chip, pvalue);
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
return rt9471_get_value_by_field_range(chip, F_ICHG_REG, RT9471_RANGE_ICHG, pvalue);
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
*pvalue = RT9471_ICHG_MAXUA;
|
||||
return 0;
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
return rt9471_get_value_by_field_range(chip, F_VBAT_REG, RT9471_RANGE_VCHG, pvalue);
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
|
||||
val->intval = RT9471_VCHG_MAXUV;
|
||||
return 0;
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
return rt9471_get_value_by_field_range(chip, F_AICR, RT9471_RANGE_AICR, pvalue);
|
||||
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||
return rt9471_get_value_by_field_range(chip, F_MIVR, RT9471_RANGE_MIVR, pvalue);
|
||||
case POWER_SUPPLY_PROP_USB_TYPE:
|
||||
return rt9471_get_usb_type(chip, pvalue);
|
||||
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
|
||||
return rt9471_get_value_by_field_range(chip, F_IPRE_CHG, RT9471_RANGE_IPRE, pvalue);
|
||||
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
||||
return rt9471_get_ieoc(chip, pvalue);
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
val->strval = rt9471_model;
|
||||
return 0;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = rt9471_manufacturer;
|
||||
return 0;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rt9471_vbus_gd_handler(int irqno, void *devid)
|
||||
{
|
||||
struct rt9471_chip *chip = devid;
|
||||
|
||||
power_supply_changed(chip->psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rt9471_detach_handler(int irqno, void *devid)
|
||||
{
|
||||
struct rt9471_chip *chip = devid;
|
||||
unsigned int vbus_gd;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_ST_VBUS_GD], &vbus_gd);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Only focus on really detached */
|
||||
if (vbus_gd)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
mutex_lock(&chip->var_lock);
|
||||
chip->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
|
||||
chip->psy_usb_curr = 0;
|
||||
mutex_unlock(&chip->var_lock);
|
||||
|
||||
power_supply_changed(chip->psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rt9471_bc12_done_handler(int irqno, void *devid)
|
||||
{
|
||||
struct rt9471_chip *chip = devid;
|
||||
enum power_supply_usb_type usb_type;
|
||||
unsigned int port_stat;
|
||||
int usb_curr, ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_PORT_STAT], &port_stat);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
switch (port_stat) {
|
||||
case RT9471_PORTSTAT_APPLE_10W:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
|
||||
usb_curr = 2000000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_APPLE_5W:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
|
||||
usb_curr = 1000000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_APPLE_12W:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
|
||||
usb_curr = 2400000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_SAMSUNG_10W:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_DCP;
|
||||
usb_curr = 2000000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_DCP:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_DCP;
|
||||
usb_curr = 1500000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_NSTD:
|
||||
case RT9471_PORTSTAT_SDP:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_SDP;
|
||||
usb_curr = 500000;
|
||||
break;
|
||||
case RT9471_PORTSTAT_CDP:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_CDP;
|
||||
usb_curr = 1500000;
|
||||
break;
|
||||
default:
|
||||
usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
|
||||
usb_curr = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&chip->var_lock);
|
||||
chip->psy_usb_type = usb_type;
|
||||
chip->psy_usb_curr = usb_curr;
|
||||
mutex_unlock(&chip->var_lock);
|
||||
|
||||
power_supply_changed(chip->psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rt9471_wdt_handler(int irqno, void *devid)
|
||||
{
|
||||
struct rt9471_chip *chip = devid;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_write(chip->rm_fields[F_WDT_RST], 1);
|
||||
|
||||
return ret ? IRQ_NONE : IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rt9471_otg_fault_handler(int irqno, void *devid)
|
||||
{
|
||||
struct rt9471_chip *chip = devid;
|
||||
|
||||
regulator_notifier_call_chain(chip->otg_rdev, REGULATOR_EVENT_FAIL, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define RT9471_IRQ_DESC(_name, _hwirq) \
|
||||
{ \
|
||||
.name = #_name, \
|
||||
.hwirq = _hwirq, \
|
||||
.handler = rt9471_##_name##_handler, \
|
||||
}
|
||||
|
||||
static int rt9471_register_interrupts(struct rt9471_chip *chip)
|
||||
{
|
||||
struct device *dev = chip->dev;
|
||||
static const struct {
|
||||
char *name;
|
||||
int hwirq;
|
||||
irq_handler_t handler;
|
||||
} chg_irqs[] = {
|
||||
RT9471_IRQ_DESC(vbus_gd, RT9471_IRQ_VBUS_GD),
|
||||
RT9471_IRQ_DESC(detach, RT9471_IRQ_DETACH),
|
||||
RT9471_IRQ_DESC(bc12_done, RT9471_IRQ_BC12_DONE),
|
||||
RT9471_IRQ_DESC(wdt, RT9471_IRQ_WDT),
|
||||
RT9471_IRQ_DESC(otg_fault, RT9471_IRQ_OTG_FAULT),
|
||||
}, *curr;
|
||||
int i, virq, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chg_irqs); i++) {
|
||||
curr = chg_irqs + i;
|
||||
|
||||
virq = regmap_irq_get_virq(chip->irq_chip_data, curr->hwirq);
|
||||
if (virq <= 0)
|
||||
return virq;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, virq, NULL, curr->handler,
|
||||
IRQF_ONESHOT, curr->name, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to register IRQ (%s)\n",
|
||||
curr->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regulator_ops rt9471_otg_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.set_current_limit = regulator_set_current_limit_regmap,
|
||||
.get_current_limit = regulator_get_current_limit_regmap,
|
||||
};
|
||||
|
||||
static const unsigned int rt9471_otg_microamp[] = { 500000, 1200000, };
|
||||
|
||||
static const struct regulator_desc rt9471_otg_rdesc = {
|
||||
.of_match = of_match_ptr("usb-otg-vbus-regulator"),
|
||||
.name = "rt9471-otg-vbus",
|
||||
.owner = THIS_MODULE,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.ops = &rt9471_otg_ops,
|
||||
.min_uV = RT9471_OTGCV_MINUV,
|
||||
.uV_step = RT9471_OTGCV_STEPUV,
|
||||
.n_voltages = RT9471_NUM_VOTG,
|
||||
.curr_table = rt9471_otg_microamp,
|
||||
.n_current_limits = ARRAY_SIZE(rt9471_otg_microamp),
|
||||
.enable_mask = RT9471_OTGEN_MASK,
|
||||
.enable_reg = RT9471_REG_FUNC,
|
||||
.vsel_reg = RT9471_REG_OTGCFG,
|
||||
.vsel_mask = RT9471_OTGCV_MASK,
|
||||
.csel_reg = RT9471_REG_OTGCFG,
|
||||
.csel_mask = RT9471_OTGCC_MASK,
|
||||
};
|
||||
|
||||
static int rt9471_register_otg_regulator(struct rt9471_chip *chip)
|
||||
{
|
||||
struct device *dev = chip->dev;
|
||||
struct regulator_config cfg = { .dev = dev, .driver_data = chip };
|
||||
|
||||
chip->otg_rdev = devm_regulator_register(dev, &rt9471_otg_rdesc, &cfg);
|
||||
|
||||
return PTR_ERR_OR_ZERO(chip->otg_rdev);
|
||||
}
|
||||
|
||||
static inline struct rt9471_chip *psy_device_to_chip(struct device *dev)
|
||||
{
|
||||
return power_supply_get_drvdata(to_power_supply(dev));
|
||||
}
|
||||
|
||||
static ssize_t sysoff_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rt9471_chip *chip = psy_device_to_chip(dev);
|
||||
unsigned int sysoff_enable;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_BATFET_DIS], &sysoff_enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", sysoff_enable);
|
||||
}
|
||||
|
||||
static ssize_t sysoff_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct rt9471_chip *chip = psy_device_to_chip(dev);
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_write(chip->rm_fields[F_BATFET_DIS], !!tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t port_detect_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rt9471_chip *chip = psy_device_to_chip(dev);
|
||||
unsigned int bc12_enable;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_BC12_EN], &bc12_enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", bc12_enable);
|
||||
}
|
||||
|
||||
static ssize_t port_detect_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct rt9471_chip *chip = psy_device_to_chip(dev);
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_write(chip->rm_fields[F_BC12_EN], !!tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(sysoff_enable);
|
||||
static DEVICE_ATTR_RW(port_detect_enable);
|
||||
|
||||
static struct attribute *rt9471_sysfs_attrs[] = {
|
||||
&dev_attr_sysoff_enable.attr,
|
||||
&dev_attr_port_detect_enable.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(rt9471_sysfs);
|
||||
|
||||
static int rt9471_register_psy(struct rt9471_chip *chip)
|
||||
{
|
||||
struct device *dev = chip->dev;
|
||||
struct power_supply_desc *desc = &chip->psy_desc;
|
||||
struct power_supply_config cfg = {};
|
||||
char *psy_name;
|
||||
|
||||
cfg.drv_data = chip;
|
||||
cfg.of_node = dev->of_node;
|
||||
cfg.attr_grp = rt9471_sysfs_groups;
|
||||
|
||||
psy_name = devm_kasprintf(dev, GFP_KERNEL, "rt9471-%s", dev_name(dev));
|
||||
if (!psy_name)
|
||||
return -ENOMEM;
|
||||
|
||||
desc->name = psy_name;
|
||||
desc->type = POWER_SUPPLY_TYPE_USB;
|
||||
desc->usb_types = rt9471_charger_usb_types;
|
||||
desc->num_usb_types = ARRAY_SIZE(rt9471_charger_usb_types);
|
||||
desc->properties = rt9471_charger_properties;
|
||||
desc->num_properties = ARRAY_SIZE(rt9471_charger_properties);
|
||||
desc->get_property = rt9471_charger_get_property;
|
||||
desc->set_property = rt9471_charger_set_property;
|
||||
desc->property_is_writeable = rt9471_charger_property_is_writeable;
|
||||
|
||||
chip->psy = devm_power_supply_register(dev, desc, &cfg);
|
||||
|
||||
return PTR_ERR_OR_ZERO(chip->psy);
|
||||
}
|
||||
|
||||
static const struct regmap_irq rt9471_regmap_irqs[] = {
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_BC12_DONE, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_DETACH, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_RECHG, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_DONE, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_BG_CHG, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_IE0C, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_RDY, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_VBUS_GD, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_BATOV, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_SYSOV, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_TOUT, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_BUSUV, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_THREG, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_AICR, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_MIVR, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_SYS_SHORT, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_SYS_MIN, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_AICC_DONE, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_PE_DONE, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_COLD, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_COOL, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_WARM, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_HOT, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_FAULT, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_LBP, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_CC, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_WDT, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_VAC_OV, 8),
|
||||
REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTP, 8),
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip rt9471_irq_chip = {
|
||||
.name = "rt9471-irqs",
|
||||
.status_base = RT9471_REG_IRQ0,
|
||||
.mask_base = RT9471_REG_MASK0,
|
||||
.num_regs = RT9471_NUM_IRQ_REGS,
|
||||
.irqs = rt9471_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(rt9471_regmap_irqs),
|
||||
};
|
||||
|
||||
static const struct reg_sequence rt9471_init_regs[] = {
|
||||
REG_SEQ0(RT9471_REG_INFO, 0x80), /* REG_RST */
|
||||
REG_SEQ0(RT9471_REG_TOP, 0xC0), /* WDT = 0 */
|
||||
REG_SEQ0(RT9471_REG_FUNC, 0x01), /* BATFET_DIS_DLY = 0 */
|
||||
REG_SEQ0(RT9471_REG_IBUS, 0x0A), /* AUTO_AICR = 0 */
|
||||
REG_SEQ0(RT9471_REG_VBUS, 0xC6), /* VAC_OVP = 14V */
|
||||
REG_SEQ0(RT9471_REG_JEITA, 0x38), /* JEITA = 0 */
|
||||
REG_SEQ0(RT9471_REG_DPDMDET, 0x31), /* BC12_EN = 0, DCP_DP_OPT = 1 */
|
||||
};
|
||||
|
||||
static int rt9471_check_devinfo(struct rt9471_chip *chip)
|
||||
{
|
||||
struct device *dev = chip->dev;
|
||||
unsigned int dev_id;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_read(chip->rm_fields[F_DEVICE_ID], &dev_id);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to read device_id\n");
|
||||
|
||||
switch (dev_id) {
|
||||
case RT9470_DEVID:
|
||||
case RT9470D_DEVID:
|
||||
case RT9471_DEVID:
|
||||
case RT9471D_DEVID:
|
||||
return 0;
|
||||
default:
|
||||
return dev_err_probe(dev, -ENODEV, "Incorrect device id\n");
|
||||
}
|
||||
}
|
||||
|
||||
static bool rt9471_accessible_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x00 ... 0x0F:
|
||||
case 0x10 ... 0x13:
|
||||
case 0x20 ... 0x33:
|
||||
case 0x40 ... 0xA1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config rt9471_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xA1,
|
||||
.writeable_reg = rt9471_accessible_reg,
|
||||
.readable_reg = rt9471_accessible_reg,
|
||||
};
|
||||
|
||||
static int rt9471_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct device *dev = &i2c->dev;
|
||||
struct rt9471_chip *chip;
|
||||
struct gpio_desc *ce_gpio;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = dev;
|
||||
mutex_init(&chip->var_lock);
|
||||
i2c_set_clientdata(i2c, chip);
|
||||
|
||||
/* Default pull charge enable gpio to make 'CHG_EN' by SW control only */
|
||||
ce_gpio = devm_gpiod_get_optional(dev, "charge-enable", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ce_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ce_gpio),
|
||||
"Failed to config charge enable gpio\n");
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &rt9471_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
|
||||
|
||||
chip->regmap = regmap;
|
||||
|
||||
ret = devm_regmap_field_bulk_alloc(dev, regmap, chip->rm_fields,
|
||||
rt9471_reg_fields,
|
||||
ARRAY_SIZE(rt9471_reg_fields));
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to alloc regmap field\n");
|
||||
|
||||
ret = rt9471_check_devinfo(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_register_patch(regmap, rt9471_init_regs,
|
||||
ARRAY_SIZE(rt9471_init_regs));
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to init registers\n");
|
||||
|
||||
ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
|
||||
&rt9471_irq_chip, &chip->irq_chip_data);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to add IRQ chip\n");
|
||||
|
||||
ret = rt9471_register_psy(chip);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to register psy\n");
|
||||
|
||||
ret = rt9471_register_otg_regulator(chip);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to register otg\n");
|
||||
|
||||
ret = rt9471_register_interrupts(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* After IRQs are all initialized, enable port detection by default */
|
||||
return regmap_field_write(chip->rm_fields[F_BC12_EN], 1);
|
||||
}
|
||||
|
||||
static void rt9471_shutdown(struct i2c_client *i2c)
|
||||
{
|
||||
struct rt9471_chip *chip = i2c_get_clientdata(i2c);
|
||||
|
||||
/*
|
||||
* There's no external reset pin. Do register reset to guarantee charger
|
||||
* function is normal after shutdown
|
||||
*/
|
||||
regmap_field_write(chip->rm_fields[F_REG_RST], 1);
|
||||
}
|
||||
|
||||
static const struct of_device_id rt9471_of_device_id[] = {
|
||||
{ .compatible = "richtek,rt9471" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rt9471_of_device_id);
|
||||
|
||||
static struct i2c_driver rt9471_driver = {
|
||||
.driver = {
|
||||
.name = "rt9471",
|
||||
.of_match_table = rt9471_of_device_id,
|
||||
},
|
||||
.probe_new = rt9471_probe,
|
||||
.shutdown = rt9471_shutdown,
|
||||
};
|
||||
module_i2c_driver(rt9471_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Richtek RT9471 charger driver");
|
||||
MODULE_AUTHOR("Alina Yu <alina_yu@richtek.com>");
|
||||
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -306,8 +306,7 @@ static int map_get_value(struct battery_property_map *map, const char *key,
|
|||
char buf[MAX_KEYLENGTH];
|
||||
int cr;
|
||||
|
||||
strncpy(buf, key, MAX_KEYLENGTH);
|
||||
buf[MAX_KEYLENGTH-1] = '\0';
|
||||
strscpy(buf, key, MAX_KEYLENGTH);
|
||||
|
||||
cr = strnlen(buf, MAX_KEYLENGTH) - 1;
|
||||
if (cr < 0)
|
||||
|
|
|
@ -726,11 +726,9 @@ twl4030_bci_mode_show(struct device *dev,
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(modes); i++)
|
||||
if (mode == i)
|
||||
len += scnprintf(buf+len, PAGE_SIZE-len,
|
||||
"[%s] ", modes[i]);
|
||||
len += sysfs_emit_at(buf, len, "[%s] ", modes[i]);
|
||||
else
|
||||
len += scnprintf(buf+len, PAGE_SIZE-len,
|
||||
"%s ", modes[i]);
|
||||
len += sysfs_emit_at(buf, len, "%s ", modes[i]);
|
||||
buf[len-1] = '\n';
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ static ssize_t charger_state_show(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", charge);
|
||||
return sysfs_emit(buf, "%s\n", charge);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(charger_state);
|
||||
|
|
Loading…
Reference in New Issue