^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Summit Microelectronics SMB347 Battery Charger Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2011, Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Authors: Bruce E. Robertson <bruce.e.robertson@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Mika Westerberg <mika.westerberg@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <dt-bindings/power/summit,smb347-charger.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Use the default compensation method */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define SMB3XX_SOFT_TEMP_COMPENSATE_DEFAULT -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Use default factory programmed value for hard/soft temperature limit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define SMB3XX_TEMP_USE_DEFAULT -273
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Configuration registers. These are mirrored to volatile RAM and can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * written once %CMD_A_ALLOW_WRITE is set in %CMD_A register. They will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * reloaded from non-volatile registers after POR.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CFG_CHARGE_CURRENT 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CFG_CHARGE_CURRENT_FCC_MASK 0xe0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CFG_CHARGE_CURRENT_FCC_SHIFT 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define CFG_CHARGE_CURRENT_PCC_MASK 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define CFG_CHARGE_CURRENT_PCC_SHIFT 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define CFG_CHARGE_CURRENT_TC_MASK 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define CFG_CURRENT_LIMIT 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define CFG_CURRENT_LIMIT_DC_MASK 0xf0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define CFG_CURRENT_LIMIT_DC_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define CFG_CURRENT_LIMIT_USB_MASK 0x0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define CFG_FLOAT_VOLTAGE 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define CFG_FLOAT_VOLTAGE_FLOAT_MASK 0x3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define CFG_FLOAT_VOLTAGE_THRESHOLD_MASK 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define CFG_STAT 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define CFG_STAT_DISABLED BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define CFG_STAT_ACTIVE_HIGH BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define CFG_PIN 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define CFG_PIN_EN_CTRL_MASK 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define CFG_PIN_EN_CTRL_ACTIVE_HIGH 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define CFG_PIN_EN_CTRL_ACTIVE_LOW 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define CFG_PIN_EN_APSD_IRQ BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define CFG_PIN_EN_CHARGER_ERROR BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define CFG_PIN_EN_CTRL BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define CFG_THERM 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define CFG_THERM_SOFT_HOT_COMPENSATION_MASK 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define CFG_THERM_SOFT_COLD_COMPENSATION_MASK 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define CFG_THERM_MONITOR_DISABLED BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define CFG_SYSOK 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define CFG_OTHER 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define CFG_OTHER_RID_MASK 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define CFG_OTHER_RID_ENABLED_AUTO_OTG 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define CFG_OTG 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define CFG_OTG_TEMP_THRESHOLD_MASK 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define CFG_OTG_TEMP_THRESHOLD_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define CFG_OTG_CC_COMPENSATION_MASK 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define CFG_OTG_CC_COMPENSATION_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define CFG_TEMP_LIMIT 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define CFG_TEMP_LIMIT_SOFT_HOT_MASK 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define CFG_TEMP_LIMIT_SOFT_HOT_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define CFG_TEMP_LIMIT_SOFT_COLD_MASK 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define CFG_TEMP_LIMIT_SOFT_COLD_SHIFT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define CFG_TEMP_LIMIT_HARD_HOT_MASK 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define CFG_TEMP_LIMIT_HARD_HOT_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define CFG_TEMP_LIMIT_HARD_COLD_MASK 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define CFG_TEMP_LIMIT_HARD_COLD_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define CFG_FAULT_IRQ 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define CFG_FAULT_IRQ_DCIN_UV BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define CFG_STATUS_IRQ 0x0d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define CFG_STATUS_IRQ_TERMINATION_OR_TAPER BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define CFG_STATUS_IRQ_CHARGE_TIMEOUT BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define CFG_ADDRESS 0x0e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Command registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define CMD_A 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define CMD_A_CHG_ENABLED BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define CMD_A_SUSPEND_ENABLED BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define CMD_A_ALLOW_WRITE BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define CMD_B 0x31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define CMD_C 0x33
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Interrupt Status registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define IRQSTAT_A 0x35
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define IRQSTAT_C 0x37
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define IRQSTAT_C_TERMINATION_STAT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define IRQSTAT_C_TERMINATION_IRQ BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define IRQSTAT_C_TAPER_IRQ BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define IRQSTAT_D 0x38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define IRQSTAT_D_CHARGE_TIMEOUT_STAT BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define IRQSTAT_D_CHARGE_TIMEOUT_IRQ BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define IRQSTAT_E 0x39
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define IRQSTAT_E_USBIN_UV_STAT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define IRQSTAT_E_USBIN_UV_IRQ BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define IRQSTAT_E_DCIN_UV_STAT BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define IRQSTAT_E_DCIN_UV_IRQ BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define IRQSTAT_F 0x3a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Status registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define STAT_A 0x3b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define STAT_A_FLOAT_VOLTAGE_MASK 0x3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define STAT_B 0x3c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define STAT_C 0x3d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define STAT_C_CHG_ENABLED BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define STAT_C_HOLDOFF_STAT BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define STAT_C_CHG_MASK 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define STAT_C_CHG_SHIFT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #define STAT_C_CHG_TERM BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define STAT_C_CHARGER_ERROR BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define STAT_E 0x3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define SMB347_MAX_REGISTER 0x3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * struct smb347_charger - smb347 charger instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * @dev: pointer to device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * @regmap: pointer to driver regmap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * @mains: power_supply instance for AC/DC power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * @usb: power_supply instance for USB power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @id: SMB charger ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * @mains_online: is AC/DC input connected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @usb_online: is USB input connected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * @charging_enabled: is charging enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * @irq_unsupported: is interrupt unsupported by SMB hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * @max_charge_current: maximum current (in uA) the battery can be charged
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * @max_charge_voltage: maximum voltage (in uV) the battery can be charged
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * @pre_charge_current: current (in uA) to use in pre-charging phase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * @termination_current: current (in uA) used to determine when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * charging cycle terminates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @pre_to_fast_voltage: voltage (in uV) treshold used for transitioning to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * pre-charge to fast charge mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * @mains_current_limit: maximum input current drawn from AC/DC input (in uA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * @usb_hc_current_limit: maximum input high current (in uA) drawn from USB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * @chip_temp_threshold: die temperature where device starts limiting charge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * current [%100 - %130] (in degree C)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @soft_cold_temp_limit: soft cold temperature limit [%0 - %15] (in degree C),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * granularity is 5 deg C.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * @soft_hot_temp_limit: soft hot temperature limit [%40 - %55] (in degree C),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * granularity is 5 deg C.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * @hard_cold_temp_limit: hard cold temperature limit [%-5 - %10] (in degree C),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * granularity is 5 deg C.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * @hard_hot_temp_limit: hard hot temperature limit [%50 - %65] (in degree C),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * granularity is 5 deg C.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * @suspend_on_hard_temp_limit: suspend charging when hard limit is hit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * @soft_temp_limit_compensation: compensation method when soft temperature
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * limit is hit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * @charge_current_compensation: current (in uA) for charging compensation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * current when temperature hits soft limits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * @use_mains: AC/DC input can be used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * @use_usb: USB input can be used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * @use_usb_otg: USB OTG output can be used (not implemented yet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * @enable_control: how charging enable/disable is controlled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * (driver/pin controls)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * @use_main, @use_usb, and @use_usb_otg are means to enable/disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * hardware support for these. This is useful when we want to have for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * example OTG charging controlled via OTG transceiver driver and not by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * the SMB347 hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * Hard and soft temperature limit values are given as described in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * device data sheet and assuming NTC beta value is %3750. Even if this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * not the case, these values should be used. They can be mapped to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * corresponding NTC beta values with the help of table %2 in the data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * sheet. So for example if NTC beta is %3375 and we want to program hard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * hot limit to be %53 deg C, @hard_hot_temp_limit should be set to %50.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * If zero value is given in any of the current and voltage values, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * factory programmed default will be used. For soft/hard temperature
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * values, pass in %SMB3XX_TEMP_USE_DEFAULT instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct smb347_charger {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct power_supply *mains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct power_supply *usb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) bool mains_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) bool usb_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) bool charging_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) bool irq_unsupported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) unsigned int max_charge_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) unsigned int max_charge_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) unsigned int pre_charge_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned int termination_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned int pre_to_fast_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) unsigned int mains_current_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) unsigned int usb_hc_current_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) unsigned int chip_temp_threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) int soft_cold_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int soft_hot_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int hard_cold_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) int hard_hot_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) bool suspend_on_hard_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) unsigned int soft_temp_limit_compensation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned int charge_current_compensation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) bool use_mains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) bool use_usb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) bool use_usb_otg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) unsigned int enable_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) enum smb_charger_chipid {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) SMB345,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) SMB347,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) SMB358,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) NUM_CHIP_TYPES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /* Fast charge current in uA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static const unsigned int fcc_tbl[NUM_CHIP_TYPES][8] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) [SMB345] = { 200000, 450000, 600000, 900000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 1300000, 1500000, 1800000, 2000000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) [SMB347] = { 700000, 900000, 1200000, 1500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 1800000, 2000000, 2200000, 2500000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) [SMB358] = { 200000, 450000, 600000, 900000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 1300000, 1500000, 1800000, 2000000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* Pre-charge current in uA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static const unsigned int pcc_tbl[NUM_CHIP_TYPES][4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) [SMB345] = { 150000, 250000, 350000, 450000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) [SMB347] = { 100000, 150000, 200000, 250000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) [SMB358] = { 150000, 250000, 350000, 450000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* Termination current in uA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static const unsigned int tc_tbl[NUM_CHIP_TYPES][8] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) [SMB345] = { 30000, 40000, 60000, 80000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 100000, 125000, 150000, 200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) [SMB347] = { 37500, 50000, 100000, 150000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 200000, 250000, 500000, 600000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) [SMB358] = { 30000, 40000, 60000, 80000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 100000, 125000, 150000, 200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* Input current limit in uA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static const unsigned int icl_tbl[NUM_CHIP_TYPES][10] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) [SMB345] = { 300000, 500000, 700000, 1000000, 1500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 1800000, 2000000, 2000000, 2000000, 2000000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) [SMB347] = { 300000, 500000, 700000, 900000, 1200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 1500000, 1800000, 2000000, 2200000, 2500000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) [SMB358] = { 300000, 500000, 700000, 1000000, 1500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 1800000, 2000000, 2000000, 2000000, 2000000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* Charge current compensation in uA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static const unsigned int ccc_tbl[NUM_CHIP_TYPES][4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) [SMB345] = { 200000, 450000, 600000, 900000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) [SMB347] = { 250000, 700000, 900000, 1200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) [SMB358] = { 200000, 450000, 600000, 900000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* Convert register value to current using lookup table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (val >= size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return tbl[val];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* Convert current to register value using lookup table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) for (i = 0; i < size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (val < tbl[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return i > 0 ? i - 1 : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^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) * smb347_update_ps_status - refreshes the power source status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * @smb: pointer to smb347 charger instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * Function checks whether any power source is connected to the charger and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * updates internal state accordingly. If there is a change to previous state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * function returns %1, otherwise %0 and negative errno in case of errror.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) static int smb347_update_ps_status(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) bool usb = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) bool dc = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) ret = regmap_read(smb->regmap, IRQSTAT_E, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * Dc and usb are set depending on whether they are enabled in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * platform data _and_ whether corresponding undervoltage is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (smb->use_mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) dc = !(val & IRQSTAT_E_DCIN_UV_STAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) usb = !(val & IRQSTAT_E_USBIN_UV_STAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ret = smb->mains_online != dc || smb->usb_online != usb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) smb->mains_online = dc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) smb->usb_online = usb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * smb347_is_ps_online - returns whether input power source is connected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * @smb: pointer to smb347 charger instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * Returns %true if input power source is connected. Note that this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * dependent on what platform has configured for usable power sources. For
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * example if USB is disabled, this will return %false even if the USB cable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * is connected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static bool smb347_is_ps_online(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return smb->usb_online || smb->mains_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * smb347_charging_status - returns status of charging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * @smb: pointer to smb347 charger instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * Function returns charging status. %0 means no charging is in progress,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * %1 means pre-charging, %2 fast-charging and %3 taper-charging.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static int smb347_charging_status(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (!smb347_is_ps_online(smb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ret = regmap_read(smb->regmap, STAT_C, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return (val & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static int smb347_charging_set(struct smb347_charger *smb, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (smb->enable_control != SMB3XX_CHG_ENABLE_SW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) dev_dbg(smb->dev, "charging enable/disable in SW disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (smb->charging_enabled != enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ret = regmap_update_bits(smb->regmap, CMD_A, CMD_A_CHG_ENABLED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) enable ? CMD_A_CHG_ENABLED : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) smb->charging_enabled = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static inline int smb347_charging_enable(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return smb347_charging_set(smb, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static inline int smb347_charging_disable(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return smb347_charging_set(smb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static int smb347_start_stop_charging(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * Depending on whether valid power source is connected or not, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * disable or enable the charging. We do it manually because it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * depends on how the platform has configured the valid inputs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (smb347_is_ps_online(smb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = smb347_charging_enable(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dev_err(smb->dev, "failed to enable charging\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) ret = smb347_charging_disable(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) dev_err(smb->dev, "failed to disable charging\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static int smb347_set_charge_current(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) unsigned int id = smb->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (smb->max_charge_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) ret = current_to_hw(fcc_tbl[id], ARRAY_SIZE(fcc_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) smb->max_charge_current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) CFG_CHARGE_CURRENT_FCC_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) ret << CFG_CHARGE_CURRENT_FCC_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (smb->pre_charge_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) ret = current_to_hw(pcc_tbl[id], ARRAY_SIZE(pcc_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) smb->pre_charge_current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) CFG_CHARGE_CURRENT_PCC_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) ret << CFG_CHARGE_CURRENT_PCC_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (smb->termination_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) ret = current_to_hw(tc_tbl[id], ARRAY_SIZE(tc_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) smb->termination_current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) CFG_CHARGE_CURRENT_TC_MASK, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static int smb347_set_current_limits(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) unsigned int id = smb->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (smb->mains_current_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) ret = current_to_hw(icl_tbl[id], ARRAY_SIZE(icl_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) smb->mains_current_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) CFG_CURRENT_LIMIT_DC_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) ret << CFG_CURRENT_LIMIT_DC_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (smb->usb_hc_current_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) ret = current_to_hw(icl_tbl[id], ARRAY_SIZE(icl_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) smb->usb_hc_current_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) CFG_CURRENT_LIMIT_USB_MASK, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return ret;
^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) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static int smb347_set_voltage_limits(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (smb->pre_to_fast_voltage) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) ret = smb->pre_to_fast_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* uV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ret = clamp_val(ret, 2400000, 3000000) - 2400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) ret /= 200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) CFG_FLOAT_VOLTAGE_THRESHOLD_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) ret << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (smb->max_charge_voltage) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) ret = smb->max_charge_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /* uV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ret = clamp_val(ret, 3500000, 4500000) - 3500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) ret /= 20000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) CFG_FLOAT_VOLTAGE_FLOAT_MASK, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static int smb347_set_temp_limits(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) unsigned int id = smb->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) bool enable_therm_monitor = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (smb->chip_temp_threshold) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) val = smb->chip_temp_threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /* degree C */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) val = clamp_val(val, 100, 130) - 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) val /= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) ret = regmap_update_bits(smb->regmap, CFG_OTG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) CFG_OTG_TEMP_THRESHOLD_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) val << CFG_OTG_TEMP_THRESHOLD_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (smb->soft_cold_temp_limit != SMB3XX_TEMP_USE_DEFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) val = smb->soft_cold_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) val = clamp_val(val, 0, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) val /= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /* this goes from higher to lower so invert the value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) val = ~val & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) CFG_TEMP_LIMIT_SOFT_COLD_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) val << CFG_TEMP_LIMIT_SOFT_COLD_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) enable_therm_monitor = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (smb->soft_hot_temp_limit != SMB3XX_TEMP_USE_DEFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) val = smb->soft_hot_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) val = clamp_val(val, 40, 55) - 40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) val /= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) CFG_TEMP_LIMIT_SOFT_HOT_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) val << CFG_TEMP_LIMIT_SOFT_HOT_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) enable_therm_monitor = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (smb->hard_cold_temp_limit != SMB3XX_TEMP_USE_DEFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) val = smb->hard_cold_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) val = clamp_val(val, -5, 10) + 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) val /= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) /* this goes from higher to lower so invert the value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) val = ~val & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) CFG_TEMP_LIMIT_HARD_COLD_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) val << CFG_TEMP_LIMIT_HARD_COLD_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) enable_therm_monitor = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (smb->hard_hot_temp_limit != SMB3XX_TEMP_USE_DEFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) val = smb->hard_hot_temp_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) val = clamp_val(val, 50, 65) - 50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) val /= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) CFG_TEMP_LIMIT_HARD_HOT_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) val << CFG_TEMP_LIMIT_HARD_HOT_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) enable_therm_monitor = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) * If any of the temperature limits are set, we also enable the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * thermistor monitoring.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * When soft limits are hit, the device will start to compensate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) * current and/or voltage depending on the configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * When hard limit is hit, the device will suspend charging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * depending on the configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (enable_therm_monitor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) ret = regmap_update_bits(smb->regmap, CFG_THERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) CFG_THERM_MONITOR_DISABLED, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) if (smb->suspend_on_hard_temp_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) ret = regmap_update_bits(smb->regmap, CFG_SYSOK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (smb->soft_temp_limit_compensation !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) SMB3XX_SOFT_TEMP_COMPENSATE_DEFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) val = smb->soft_temp_limit_compensation & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) ret = regmap_update_bits(smb->regmap, CFG_THERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) CFG_THERM_SOFT_HOT_COMPENSATION_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) ret = regmap_update_bits(smb->regmap, CFG_THERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) CFG_THERM_SOFT_COLD_COMPENSATION_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (smb->charge_current_compensation) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) val = current_to_hw(ccc_tbl[id], ARRAY_SIZE(ccc_tbl[id]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) smb->charge_current_compensation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (val < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) ret = regmap_update_bits(smb->regmap, CFG_OTG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) CFG_OTG_CC_COMPENSATION_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * smb347_set_writable - enables/disables writing to non-volatile registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * @smb: pointer to smb347 charger instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * You can enable/disable writing to the non-volatile configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * registers by calling this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) * Returns %0 on success and negative errno in case of failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) static int smb347_set_writable(struct smb347_charger *smb, bool writable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) return regmap_update_bits(smb->regmap, CMD_A, CMD_A_ALLOW_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) writable ? CMD_A_ALLOW_WRITE : 0);
^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 smb347_hw_init(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) ret = smb347_set_writable(smb, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * Program the platform specific configuration values to the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) ret = smb347_set_charge_current(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) ret = smb347_set_current_limits(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) ret = smb347_set_voltage_limits(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) ret = smb347_set_temp_limits(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) /* If USB charging is disabled we put the USB in suspend mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (!smb->use_usb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) ret = regmap_update_bits(smb->regmap, CMD_A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) CMD_A_SUSPEND_ENABLED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) CMD_A_SUSPEND_ENABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) * If configured by platform data, we enable hardware Auto-OTG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) * support for driving VBUS. Otherwise we disable it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) ret = regmap_update_bits(smb->regmap, CFG_OTHER, CFG_OTHER_RID_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) smb->use_usb_otg ? CFG_OTHER_RID_ENABLED_AUTO_OTG : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) /* Activate pin control, making it writable. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) switch (smb->enable_control) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) case SMB3XX_CHG_ENABLE_PIN_ACTIVE_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) case SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) ret = regmap_set_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) * Make the charging functionality controllable by a write to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) * command register unless pin control is specified in the platform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) * data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) switch (smb->enable_control) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) case SMB3XX_CHG_ENABLE_PIN_ACTIVE_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) val = CFG_PIN_EN_CTRL_ACTIVE_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) case SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) val = CFG_PIN_EN_CTRL_ACTIVE_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CTRL_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) /* Disable Automatic Power Source Detection (APSD) interrupt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_APSD_IRQ, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) ret = smb347_update_ps_status(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) ret = smb347_start_stop_charging(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) smb347_set_writable(smb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) static irqreturn_t smb347_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) struct smb347_charger *smb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) unsigned int stat_c, irqstat_c, irqstat_d, irqstat_e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) bool handled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) /* SMB347 it needs at least 20ms for setting IRQSTAT_E_*IN_UV_IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) usleep_range(25000, 35000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) ret = regmap_read(smb->regmap, STAT_C, &stat_c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) dev_warn(smb->dev, "reading STAT_C failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) ret = regmap_read(smb->regmap, IRQSTAT_C, &irqstat_c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) dev_warn(smb->dev, "reading IRQSTAT_C failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) ret = regmap_read(smb->regmap, IRQSTAT_D, &irqstat_d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) dev_warn(smb->dev, "reading IRQSTAT_D failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) ret = regmap_read(smb->regmap, IRQSTAT_E, &irqstat_e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) dev_warn(smb->dev, "reading IRQSTAT_E failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * If we get charger error we report the error back to user.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) * If the error is recovered charging will resume again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (stat_c & STAT_C_CHARGER_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) dev_err(smb->dev, "charging stopped due to charger error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) if (smb->use_mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) power_supply_changed(smb->mains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) power_supply_changed(smb->usb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) handled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * If we reached the termination current the battery is charged and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * we can update the status now. Charging is automatically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * disabled by the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (smb->use_mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) power_supply_changed(smb->mains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) if (smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) power_supply_changed(smb->usb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) dev_dbg(smb->dev, "going to HW maintenance mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) handled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) * If we got a charger timeout INT that means the charge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) * full is not detected with in charge timeout value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_IRQ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) dev_dbg(smb->dev, "total Charge Timeout INT received\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (irqstat_d & IRQSTAT_D_CHARGE_TIMEOUT_STAT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) dev_warn(smb->dev, "charging stopped due to timeout\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (smb->use_mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) power_supply_changed(smb->mains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) power_supply_changed(smb->usb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) handled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * If we got an under voltage interrupt it means that AC/USB input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * was connected or disconnected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (smb347_update_ps_status(smb) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) smb347_start_stop_charging(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (smb->use_mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) power_supply_changed(smb->mains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) power_supply_changed(smb->usb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) handled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return handled ? IRQ_HANDLED : IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) static int smb347_irq_set(struct smb347_charger *smb, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (smb->irq_unsupported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ret = smb347_set_writable(smb, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * Enable/disable interrupts for:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) * - under voltage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) * - termination current reached
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) * - charger timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) * - charger error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) ret = regmap_update_bits(smb->regmap, CFG_FAULT_IRQ, 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) enable ? CFG_FAULT_IRQ_DCIN_UV : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) ret = regmap_update_bits(smb->regmap, CFG_STATUS_IRQ, 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) enable ? (CFG_STATUS_IRQ_TERMINATION_OR_TAPER |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) CFG_STATUS_IRQ_CHARGE_TIMEOUT) : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CHARGER_ERROR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) enable ? CFG_PIN_EN_CHARGER_ERROR : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) smb347_set_writable(smb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) return ret;
^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) static inline int smb347_irq_enable(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) return smb347_irq_set(smb, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) static inline int smb347_irq_disable(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) return smb347_irq_set(smb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) static int smb347_irq_init(struct smb347_charger *smb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) ret = devm_request_threaded_irq(smb->dev, client->irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) smb347_interrupt, IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) client->name, smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) ret = smb347_set_writable(smb, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * Configure the STAT output to be suitable for interrupts: disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * all other output (except interrupts) and make it active low.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) ret = regmap_update_bits(smb->regmap, CFG_STAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) CFG_STAT_ACTIVE_HIGH | CFG_STAT_DISABLED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) CFG_STAT_DISABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) smb347_set_writable(smb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * Returns the constant charge current programmed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * into the charger in uA.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) static int get_const_charge_current(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) unsigned int id = smb->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) int ret, intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) unsigned int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) if (!smb347_is_ps_online(smb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) ret = regmap_read(smb->regmap, STAT_B, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * The current value is composition of FCC and PCC values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) * and we can detect which table to use from bit 5.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (v & 0x20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) intval = hw_to_current(fcc_tbl[id],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) ARRAY_SIZE(fcc_tbl[id]), v & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) v >>= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) intval = hw_to_current(pcc_tbl[id],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) ARRAY_SIZE(pcc_tbl[id]), v & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) * Returns the constant charge voltage programmed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * into the charger in uV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) static int get_const_charge_voltage(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) int ret, intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) unsigned int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (!smb347_is_ps_online(smb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) ret = regmap_read(smb->regmap, STAT_A, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) v &= STAT_A_FLOAT_VOLTAGE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (v > 0x3d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) v = 0x3d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) intval = 3500000 + v * 20000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) return intval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) static int smb347_get_charging_status(struct smb347_charger *smb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) struct power_supply *psy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) int ret, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (psy->desc->type == POWER_SUPPLY_TYPE_USB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) if (!smb->usb_online)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) return POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (!smb->mains_online)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) return POWER_SUPPLY_STATUS_DISCHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) ret = regmap_read(smb->regmap, STAT_C, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) if ((val & STAT_C_CHARGER_ERROR) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) (val & STAT_C_HOLDOFF_STAT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * set to NOT CHARGING upon charger error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) * or charging has stopped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) status = POWER_SUPPLY_STATUS_NOT_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) if ((val & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) * set to charging if battery is in pre-charge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * fast charge or taper charging mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) status = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) } else if (val & STAT_C_CHG_TERM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) * set the status to FULL if battery is not in pre
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) * charge, fast charge or taper charging mode AND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) * charging is terminated at least once.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) status = POWER_SUPPLY_STATUS_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) * in this case no charger error or termination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) * occured but charging is not in progress!!!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) status = POWER_SUPPLY_STATUS_NOT_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) static int smb347_get_property_locked(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) enum power_supply_property prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) struct smb347_charger *smb = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) switch (prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) ret = smb347_get_charging_status(smb, psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) val->intval = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) case POWER_SUPPLY_PROP_CHARGE_TYPE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (psy->desc->type == POWER_SUPPLY_TYPE_USB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (!smb->usb_online)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (!smb->mains_online)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) * We handle trickle and pre-charging the same, and taper
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) * and none the same.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) switch (smb347_charging_status(smb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) case POWER_SUPPLY_PROP_ONLINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) val->intval = smb->usb_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) val->intval = smb->mains_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) ret = get_const_charge_voltage(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) val->intval = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) ret = get_const_charge_current(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) val->intval = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) static int smb347_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) enum power_supply_property prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) struct smb347_charger *smb = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) struct i2c_client *client = to_i2c_client(smb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) disable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) ret = smb347_get_property_locked(psy, prop, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) enable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) static enum power_supply_property smb347_properties[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) POWER_SUPPLY_PROP_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) POWER_SUPPLY_PROP_CHARGE_TYPE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) POWER_SUPPLY_PROP_ONLINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) static bool smb347_volatile_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) case IRQSTAT_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) case IRQSTAT_C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) case IRQSTAT_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) case IRQSTAT_E:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) case IRQSTAT_F:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) case STAT_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) case STAT_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) case STAT_C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) case STAT_E:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) static bool smb347_readable_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) case CFG_CHARGE_CURRENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) case CFG_CURRENT_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) case CFG_FLOAT_VOLTAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) case CFG_STAT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) case CFG_PIN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) case CFG_THERM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) case CFG_SYSOK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) case CFG_OTHER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) case CFG_OTG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) case CFG_TEMP_LIMIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) case CFG_FAULT_IRQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) case CFG_STATUS_IRQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) case CFG_ADDRESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) case CMD_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) case CMD_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) case CMD_C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) return smb347_volatile_reg(dev, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) static void smb347_dt_parse_dev_info(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) struct device *dev = smb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) smb->soft_temp_limit_compensation =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) SMB3XX_SOFT_TEMP_COMPENSATE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) * These properties come from the battery info, still we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) * pre-initialize the values. See smb347_get_battery_info() below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) smb->soft_cold_temp_limit = SMB3XX_TEMP_USE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) smb->hard_cold_temp_limit = SMB3XX_TEMP_USE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) smb->soft_hot_temp_limit = SMB3XX_TEMP_USE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) smb->hard_hot_temp_limit = SMB3XX_TEMP_USE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) /* Charging constraints */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) device_property_read_u32(dev, "summit,fast-voltage-threshold-microvolt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) &smb->pre_to_fast_voltage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) device_property_read_u32(dev, "summit,mains-current-limit-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) &smb->mains_current_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) device_property_read_u32(dev, "summit,usb-current-limit-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) &smb->usb_hc_current_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) /* For thermometer monitoring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) device_property_read_u32(dev, "summit,chip-temperature-threshold-celsius",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) &smb->chip_temp_threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) device_property_read_u32(dev, "summit,soft-compensation-method",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) &smb->soft_temp_limit_compensation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) device_property_read_u32(dev, "summit,charge-current-compensation-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) &smb->charge_current_compensation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) /* Supported charging mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) smb->use_mains = device_property_read_bool(dev, "summit,enable-mains-charging");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) smb->use_usb = device_property_read_bool(dev, "summit,enable-usb-charging");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) smb->use_usb_otg = device_property_read_bool(dev, "summit,enable-otg-charging");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) /* Select charging control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) device_property_read_u32(dev, "summit,enable-charge-control",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) &smb->enable_control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) static int smb347_get_battery_info(struct smb347_charger *smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) struct power_supply_battery_info info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) struct power_supply *supply;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (smb->mains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) supply = smb->mains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) supply = smb->usb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) err = power_supply_get_battery_info(supply, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) if (err == -ENXIO || err == -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) if (info.constant_charge_current_max_ua != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) smb->max_charge_current = info.constant_charge_current_max_ua;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) if (info.constant_charge_voltage_max_uv != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) smb->max_charge_voltage = info.constant_charge_voltage_max_uv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) if (info.precharge_current_ua != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) smb->pre_charge_current = info.precharge_current_ua;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) if (info.charge_term_current_ua != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) smb->termination_current = info.charge_term_current_ua;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) if (info.temp_alert_min != INT_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) smb->soft_cold_temp_limit = info.temp_alert_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) if (info.temp_alert_max != INT_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) smb->soft_hot_temp_limit = info.temp_alert_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) if (info.temp_min != INT_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) smb->hard_cold_temp_limit = info.temp_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) if (info.temp_max != INT_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) smb->hard_hot_temp_limit = info.temp_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) /* Suspend when battery temperature is outside hard limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) if (smb->hard_cold_temp_limit != SMB3XX_TEMP_USE_DEFAULT ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) smb->hard_hot_temp_limit != SMB3XX_TEMP_USE_DEFAULT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) smb->suspend_on_hard_temp_limit = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) static const struct regmap_config smb347_regmap = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) .reg_bits = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) .val_bits = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) .max_register = SMB347_MAX_REGISTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) .volatile_reg = smb347_volatile_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) .readable_reg = smb347_readable_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) static const struct power_supply_desc smb347_mains_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) .name = "smb347-mains",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) .type = POWER_SUPPLY_TYPE_MAINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) .get_property = smb347_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) .properties = smb347_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) .num_properties = ARRAY_SIZE(smb347_properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) static const struct power_supply_desc smb347_usb_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) .name = "smb347-usb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) .type = POWER_SUPPLY_TYPE_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) .get_property = smb347_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) .properties = smb347_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) .num_properties = ARRAY_SIZE(smb347_properties),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) static int smb347_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) struct power_supply_config mains_usb_cfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) struct device *dev = &client->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) struct smb347_charger *smb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) if (!smb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) smb->dev = &client->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) smb->id = id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) i2c_set_clientdata(client, smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) smb347_dt_parse_dev_info(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) if (!smb->use_mains && !smb->use_usb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (IS_ERR(smb->regmap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) return PTR_ERR(smb->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) mains_usb_cfg.drv_data = smb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) mains_usb_cfg.of_node = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (smb->use_mains) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) smb->mains = devm_power_supply_register(dev, &smb347_mains_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) &mains_usb_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) if (IS_ERR(smb->mains))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) return PTR_ERR(smb->mains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) if (smb->use_usb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) smb->usb = devm_power_supply_register(dev, &smb347_usb_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) &mains_usb_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) if (IS_ERR(smb->usb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) return PTR_ERR(smb->usb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) ret = smb347_get_battery_info(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) ret = smb347_hw_init(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) * Interrupt pin is optional. If it is connected, we setup the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) * interrupt support here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) if (client->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) ret = smb347_irq_init(smb, client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) dev_warn(dev, "disabling IRQ support\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) smb->irq_unsupported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) smb347_irq_enable(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) static int smb347_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) struct smb347_charger *smb = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) smb347_irq_disable(smb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) static const struct i2c_device_id smb347_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) { "smb345", SMB345 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) { "smb347", SMB347 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) { "smb358", SMB358 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) MODULE_DEVICE_TABLE(i2c, smb347_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) static const struct of_device_id smb3xx_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) { .compatible = "summit,smb345" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) { .compatible = "summit,smb347" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) { .compatible = "summit,smb358" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) MODULE_DEVICE_TABLE(of, smb3xx_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) static struct i2c_driver smb347_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) .name = "smb347",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) .of_match_table = smb3xx_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) .probe = smb347_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) .remove = smb347_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) .id_table = smb347_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) module_i2c_driver(smb347_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) MODULE_AUTHOR("Bruce E. Robertson <bruce.e.robertson@intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) MODULE_DESCRIPTION("SMB347 battery charger driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) MODULE_LICENSE("GPL");