^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (c) 2014, Sony Mobile Communications Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This driver is for the multi-block Switch-Mode Battery Charger and Boost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (SMBB) hardware, found in Qualcomm PM8941 PMICs. The charger is an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * integrated, single-cell lithium-ion battery charger.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Sub-components:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * - Charger core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * - Buck
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * - DC charge-path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * - USB charge-path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * - Battery interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * - Boost (not implemented)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * - Misc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * - HF-Buck
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/extcon-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/regulator/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define SMBB_CHG_VMAX 0x040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define SMBB_CHG_VSAFE 0x041
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define SMBB_CHG_CFG 0x043
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define SMBB_CHG_IMAX 0x044
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define SMBB_CHG_ISAFE 0x045
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define SMBB_CHG_VIN_MIN 0x047
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define SMBB_CHG_CTRL 0x049
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define CTRL_EN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define SMBB_CHG_VBAT_WEAK 0x052
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SMBB_CHG_IBAT_TERM_CHG 0x05b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IBAT_TERM_CHG_IEOC BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define IBAT_TERM_CHG_IEOC_BMS BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define IBAT_TERM_CHG_IEOC_CHG 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define SMBB_CHG_VBAT_DET 0x05d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define SMBB_CHG_TCHG_MAX_EN 0x060
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define TCHG_MAX_EN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define SMBB_CHG_WDOG_TIME 0x062
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define SMBB_CHG_WDOG_EN 0x065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define WDOG_EN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define SMBB_BUCK_REG_MODE 0x174
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define BUCK_REG_MODE BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define BUCK_REG_MODE_VBAT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define BUCK_REG_MODE_VSYS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define SMBB_BAT_PRES_STATUS 0x208
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define PRES_STATUS_BAT_PRES BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define SMBB_BAT_TEMP_STATUS 0x209
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define TEMP_STATUS_OK BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define TEMP_STATUS_HOT BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define SMBB_BAT_BTC_CTRL 0x249
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define BTC_CTRL_COMP_EN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define BTC_CTRL_COLD_EXT BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define BTC_CTRL_HOT_EXT_N BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define SMBB_USB_IMAX 0x344
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define SMBB_USB_OTG_CTL 0x348
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define OTG_CTL_EN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define SMBB_USB_ENUM_TIMER_STOP 0x34e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define ENUM_TIMER_STOP BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define SMBB_USB_SEC_ACCESS 0x3d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define SEC_ACCESS_MAGIC 0xa5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define SMBB_USB_REV_BST 0x3ed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define REV_BST_CHG_GONE BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define SMBB_DC_IMAX 0x444
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define SMBB_MISC_REV2 0x601
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define SMBB_MISC_BOOT_DONE 0x642
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define BOOT_DONE BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define STATUS_USBIN_VALID BIT(0) /* USB connection is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define STATUS_DCIN_VALID BIT(1) /* DC connection is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define STATUS_BAT_HOT BIT(2) /* Battery temp 1=Hot, 0=Cold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define STATUS_BAT_OK BIT(3) /* Battery temp OK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define STATUS_BAT_PRESENT BIT(4) /* Battery is present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define STATUS_CHG_DONE BIT(5) /* Charge cycle is complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define STATUS_CHG_TRKL BIT(6) /* Trickle charging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define STATUS_CHG_FAST BIT(7) /* Fast charging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define STATUS_CHG_GONE BIT(8) /* No charger is connected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) enum smbb_attr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ATTR_BAT_ISAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ATTR_BAT_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ATTR_USBIN_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) ATTR_DCIN_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ATTR_BAT_VSAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ATTR_BAT_VMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ATTR_BAT_VMIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ATTR_CHG_VDET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ATTR_VIN_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) _ATTR_CNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct smbb_charger {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) unsigned int revision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned int addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct extcon_dev *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) bool dc_disabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) bool jeita_ext_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct mutex statlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned int attr[_ATTR_CNT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct power_supply *usb_psy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct power_supply *dc_psy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct power_supply *bat_psy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct regulator_desc otg_rdesc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct regulator_dev *otg_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static const unsigned int smbb_usb_extcon_cable[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) EXTCON_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) EXTCON_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int smbb_vbat_weak_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 2100000 + index * 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int smbb_vin_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (index > 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return 5600000 + (index - 43) * 200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return 3400000 + index * 50000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static int smbb_vmax_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return 3240000 + index * 10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int smbb_vbat_det_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return 3240000 + index * 20000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static int smbb_imax_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (index < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 100000 + index * 50000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return index * 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static int smbb_bat_imax_fn(unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return index * 50000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned int widx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) unsigned int sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) sel = widx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct smbb_charger_attr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) unsigned int safe_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) unsigned int max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned int min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unsigned int fail_ok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int (*hw_fn)(unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) } smbb_charger_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) [ATTR_BAT_ISAFE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .name = "qcom,fast-charge-safe-current",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .reg = SMBB_CHG_ISAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .max = 3000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .min = 200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .hw_fn = smbb_bat_imax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .fail_ok = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) [ATTR_BAT_IMAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .name = "qcom,fast-charge-current-limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .reg = SMBB_CHG_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .safe_reg = SMBB_CHG_ISAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .max = 3000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .min = 200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .hw_fn = smbb_bat_imax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) [ATTR_DCIN_IMAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .name = "qcom,dc-current-limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .reg = SMBB_DC_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .max = 2500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .min = 100000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .hw_fn = smbb_imax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) [ATTR_BAT_VSAFE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .name = "qcom,fast-charge-safe-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .reg = SMBB_CHG_VSAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .max = 5000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) .min = 3240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .hw_fn = smbb_vmax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .fail_ok = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) [ATTR_BAT_VMAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .name = "qcom,fast-charge-high-threshold-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .reg = SMBB_CHG_VMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .safe_reg = SMBB_CHG_VSAFE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .max = 5000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .min = 3240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .hw_fn = smbb_vmax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) [ATTR_BAT_VMIN] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .name = "qcom,fast-charge-low-threshold-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .reg = SMBB_CHG_VBAT_WEAK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .max = 3600000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .min = 2100000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .hw_fn = smbb_vbat_weak_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) [ATTR_CHG_VDET] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .name = "qcom,auto-recharge-threshold-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .reg = SMBB_CHG_VBAT_DET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .max = 5000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .min = 3240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .hw_fn = smbb_vbat_det_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) [ATTR_VIN_MIN] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .name = "qcom,minimum-input-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .reg = SMBB_CHG_VIN_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .max = 9600000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .min = 4200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .hw_fn = smbb_vin_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) [ATTR_USBIN_IMAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .name = "usb-charge-current-limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .reg = SMBB_USB_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .max = 2500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .min = 100000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .hw_fn = smbb_imax_fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static int smbb_charger_attr_write(struct smbb_charger *chg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) enum smbb_attr which, unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) const struct smbb_charger_attr *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned int wval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) unsigned int out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) prop = &smbb_charger_attrs[which];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (val > prop->max || val < prop->min) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dev_err(chg->dev, "value out of range for %s [%u:%u]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) prop->name, prop->min, prop->max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (prop->safe_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) rc = regmap_read(chg->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) chg->addr + prop->safe_reg, &wval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev_err(chg->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) "unable to read safe value for '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) prop->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) wval = prop->hw_fn(wval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (val > wval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) dev_warn(chg->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) "%s above safe value, clamping at %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) prop->name, wval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) val = wval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) wval = smbb_hw_lookup(val, prop->hw_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dev_err(chg->dev, "unable to update %s", prop->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) out = prop->hw_fn(wval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (out != val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dev_warn(chg->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) "%s inaccurate, rounded to %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) prop->name, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) chg->attr[which] = out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static int smbb_charger_attr_read(struct smbb_charger *chg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) enum smbb_attr which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) const struct smbb_charger_attr *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) prop = &smbb_charger_attrs[which];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) dev_err(chg->dev, "failed to read %s\n", prop->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) val = prop->hw_fn(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) chg->attr[which] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static int smbb_charger_attr_parse(struct smbb_charger *chg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) enum smbb_attr which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) const struct smbb_charger_attr *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) prop = &smbb_charger_attrs[which];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) rc = of_property_read_u32(chg->dev->of_node, prop->name, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) rc = smbb_charger_attr_write(chg, which, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (!rc || !prop->fail_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return smbb_charger_attr_read(chg, which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) bool state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) dev_err(chg->dev, "failed to read irq line\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) mutex_lock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) chg->status |= flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) chg->status &= ~flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) mutex_unlock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) dev_dbg(chg->dev, "status = %03lx\n", chg->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) extcon_set_state_sync(chg->edev, EXTCON_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) chg->status & STATUS_USBIN_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) power_supply_changed(chg->usb_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (!chg->dc_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) power_supply_changed(chg->dc_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) mutex_lock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (val & TEMP_STATUS_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) chg->status |= STATUS_BAT_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) chg->status &= ~STATUS_BAT_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (val & TEMP_STATUS_HOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) chg->status |= STATUS_BAT_HOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) mutex_unlock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) smbb_set_line_flag(chg, irq, STATUS_CHG_GONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) power_supply_changed(chg->usb_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (!chg->dc_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) power_supply_changed(chg->dc_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct smbb_charger *chg = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) power_supply_changed(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static const struct smbb_irq {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) irqreturn_t (*handler)(int, void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) } smbb_charger_irqs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) { "chg-done", smbb_chg_done_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) { "chg-fast", smbb_chg_fast_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) { "chg-trkl", smbb_chg_trkl_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) { "bat-temp-ok", smbb_bat_temp_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) { "bat-present", smbb_bat_present_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) { "chg-gone", smbb_chg_gone_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) { "usb-valid", smbb_usb_valid_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) { "dc-valid", smbb_dc_valid_handler },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) static int smbb_usbin_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) case POWER_SUPPLY_PROP_ONLINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) mutex_lock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) val->intval = !(chg->status & STATUS_CHG_GONE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) (chg->status & STATUS_USBIN_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) mutex_unlock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) val->intval = chg->attr[ATTR_USBIN_IMAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) val->intval = 2500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) static int smbb_usbin_set_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) const union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) val->intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static int smbb_dcin_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) case POWER_SUPPLY_PROP_ONLINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) mutex_lock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) val->intval = !(chg->status & STATUS_CHG_GONE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) (chg->status & STATUS_DCIN_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) mutex_unlock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) val->intval = chg->attr[ATTR_DCIN_IMAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) val->intval = 2500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) static int smbb_dcin_set_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) const union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) val->intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) static int smbb_charger_writable_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) enum power_supply_property psp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static int smbb_battery_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) unsigned long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) mutex_lock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) status = chg->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) mutex_unlock(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (status & STATUS_CHG_GONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) else if (status & STATUS_CHG_DONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) val->intval = POWER_SUPPLY_STATUS_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) else if (!(status & STATUS_BAT_OK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) val->intval = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) else /* everything is ok for charging, but we are not... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) case POWER_SUPPLY_PROP_HEALTH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (status & STATUS_BAT_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) val->intval = POWER_SUPPLY_HEALTH_GOOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) else if (status & STATUS_BAT_HOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) val->intval = POWER_SUPPLY_HEALTH_COLD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) case POWER_SUPPLY_PROP_CHARGE_TYPE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) if (status & STATUS_CHG_FAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) else if (status & STATUS_CHG_TRKL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) case POWER_SUPPLY_PROP_PRESENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) val->intval = !!(status & STATUS_BAT_PRESENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) case POWER_SUPPLY_PROP_CURRENT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) val->intval = chg->attr[ATTR_BAT_IMAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) case POWER_SUPPLY_PROP_VOLTAGE_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) val->intval = chg->attr[ATTR_BAT_VMAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) case POWER_SUPPLY_PROP_TECHNOLOGY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) /* this charger is a single-cell lithium-ion battery charger
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) * only. If you hook up some other technology, there will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * fireworks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) val->intval = 3000000; /* single-cell li-ion low end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) static int smbb_battery_set_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) const union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) struct smbb_charger *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) case POWER_SUPPLY_PROP_CURRENT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) case POWER_SUPPLY_PROP_VOLTAGE_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static int smbb_battery_writable_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) enum power_supply_property psp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) case POWER_SUPPLY_PROP_CURRENT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) case POWER_SUPPLY_PROP_VOLTAGE_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) static enum power_supply_property smbb_charger_properties[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) POWER_SUPPLY_PROP_ONLINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static enum power_supply_property smbb_battery_properties[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) POWER_SUPPLY_PROP_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) POWER_SUPPLY_PROP_HEALTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) POWER_SUPPLY_PROP_PRESENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) POWER_SUPPLY_PROP_CHARGE_TYPE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) POWER_SUPPLY_PROP_CURRENT_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) POWER_SUPPLY_PROP_VOLTAGE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) POWER_SUPPLY_PROP_TECHNOLOGY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) static const struct reg_off_mask_default {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) unsigned int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) unsigned int mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) unsigned int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) unsigned int rev_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) } smbb_charger_setup[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* The bootloader is supposed to set this... make sure anyway. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /* Disable software timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /* Clear and disable watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) { SMBB_CHG_WDOG_TIME, 0xff, 160 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) { SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) /* Use charger based EoC detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) /* Disable GSM PA load adjustment.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * The PA signal is incorrectly connected on v2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) /* Use VBAT (not VSYS) to compensate for IR drop during fast charging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /* Enable battery temperature comparators */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) /* Stop USB enumeration timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) #if 0 /* FIXME supposedly only to disable hardware ARB termination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) /* Stop USB enumeration timer, again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) /* Enable charging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) static char *smbb_bif[] = { "smbb-bif" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static const struct power_supply_desc bat_psy_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) .name = "smbb-bif",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) .type = POWER_SUPPLY_TYPE_BATTERY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) .properties = smbb_battery_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) .num_properties = ARRAY_SIZE(smbb_battery_properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) .get_property = smbb_battery_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) .set_property = smbb_battery_set_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) .property_is_writeable = smbb_battery_writable_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) static const struct power_supply_desc usb_psy_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) .name = "smbb-usbin",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) .type = POWER_SUPPLY_TYPE_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) .properties = smbb_charger_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) .num_properties = ARRAY_SIZE(smbb_charger_properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) .get_property = smbb_usbin_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) .set_property = smbb_usbin_set_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) .property_is_writeable = smbb_charger_writable_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) static const struct power_supply_desc dc_psy_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) .name = "smbb-dcin",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) .type = POWER_SUPPLY_TYPE_MAINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) .properties = smbb_charger_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) .num_properties = ARRAY_SIZE(smbb_charger_properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) .get_property = smbb_dcin_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) .set_property = smbb_dcin_set_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) .property_is_writeable = smbb_charger_writable_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) static int smbb_chg_otg_enable(struct regulator_dev *rdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) struct smbb_charger *chg = rdev_get_drvdata(rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) OTG_CTL_EN, OTG_CTL_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) dev_err(chg->dev, "failed to update OTG_CTL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static int smbb_chg_otg_disable(struct regulator_dev *rdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) struct smbb_charger *chg = rdev_get_drvdata(rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) OTG_CTL_EN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) dev_err(chg->dev, "failed to update OTG_CTL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static int smbb_chg_otg_is_enabled(struct regulator_dev *rdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) struct smbb_charger *chg = rdev_get_drvdata(rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) unsigned int value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) rc = regmap_read(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) dev_err(chg->dev, "failed to read OTG_CTL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return !!(value & OTG_CTL_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) static const struct regulator_ops smbb_chg_otg_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) .enable = smbb_chg_otg_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) .disable = smbb_chg_otg_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) .is_enabled = smbb_chg_otg_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) static int smbb_charger_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) struct power_supply_config bat_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) struct power_supply_config usb_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) struct power_supply_config dc_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) struct smbb_charger *chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) struct regulator_config config = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) int rc, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (!chg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) chg->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) mutex_init(&chg->statlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (!chg->regmap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) dev_err(&pdev->dev, "failed to locate regmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) dev_err(&pdev->dev, "unable to read revision\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) chg->revision += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (chg->revision != 2 && chg->revision != 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) dev_err(&pdev->dev, "v1 hardware not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) for (i = 0; i < _ATTR_CNT; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) rc = smbb_charger_attr_parse(chg, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) dev_err(&pdev->dev, "failed to parse/apply settings\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) bat_cfg.drv_data = chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) bat_cfg.of_node = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) chg->bat_psy = devm_power_supply_register(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) &bat_psy_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) &bat_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (IS_ERR(chg->bat_psy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) dev_err(&pdev->dev, "failed to register battery\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return PTR_ERR(chg->bat_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) usb_cfg.drv_data = chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) usb_cfg.supplied_to = smbb_bif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) chg->usb_psy = devm_power_supply_register(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) &usb_psy_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) &usb_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (IS_ERR(chg->usb_psy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) dev_err(&pdev->dev, "failed to register USB power supply\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) return PTR_ERR(chg->usb_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (IS_ERR(chg->edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) dev_err(&pdev->dev, "failed to allocate extcon device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) rc = devm_extcon_dev_register(&pdev->dev, chg->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) dev_err(&pdev->dev, "failed to register extcon device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) if (!chg->dc_disabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) dc_cfg.drv_data = chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) dc_cfg.supplied_to = smbb_bif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) chg->dc_psy = devm_power_supply_register(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) &dc_psy_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) &dc_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (IS_ERR(chg->dc_psy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) dev_err(&pdev->dev, "failed to register DC power supply\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) return PTR_ERR(chg->dc_psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) dev_err(&pdev->dev, "failed to get irq '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) smbb_charger_irqs[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) smbb_charger_irqs[i].handler(irq, chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) smbb_charger_irqs[i].handler, IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) smbb_charger_irqs[i].name, chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) dev_err(&pdev->dev, "failed to request irq '%s'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) smbb_charger_irqs[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) * otg regulator is used to control VBUS voltage direction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * when USB switches between host and gadget mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) chg->otg_rdesc.id = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) chg->otg_rdesc.name = "otg-vbus";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) chg->otg_rdesc.ops = &smbb_chg_otg_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) chg->otg_rdesc.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) chg->otg_rdesc.type = REGULATOR_VOLTAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) chg->otg_rdesc.supply_name = "usb-otg-in";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) chg->otg_rdesc.of_match = "otg-vbus";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) config.dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) config.driver_data = chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) &config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (IS_ERR(chg->otg_reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return PTR_ERR(chg->otg_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) "qcom,jeita-extended-temp-range");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) /* Set temperature range to [35%:70%] or [25%:80%] accordingly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) chg->jeita_ext_temp ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) BTC_CTRL_COLD_EXT :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) BTC_CTRL_HOT_EXT_N);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) "unable to set %s temperature range\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) chg->jeita_ext_temp ? "JEITA extended" : "normal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) const struct reg_off_mask_default *r = &smbb_charger_setup[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (r->rev_mask & BIT(chg->revision))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) r->mask, r->value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) "unable to initializing charging, bailing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) platform_set_drvdata(pdev, chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) static int smbb_charger_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) struct smbb_charger *chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) chg = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) static const struct of_device_id smbb_charger_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) { .compatible = "qcom,pm8941-charger" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) static struct platform_driver smbb_charger_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) .probe = smbb_charger_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) .remove = smbb_charger_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) .name = "qcom-smbb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) .of_match_table = smbb_charger_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) module_platform_driver(smbb_charger_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) MODULE_LICENSE("GPL v2");