^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (C) 2018 BayLibre SAS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Battery charger driver for MAXIM 77650/77651 charger/power-supply.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mfd/max77650.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/power_supply.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define MAX77650_CHARGER_ENABLED BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define MAX77650_CHARGER_DISABLED 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define MAX77650_CHARGER_CHG_EN_MASK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define MAX77650_CHG_DETAILS_BITS(_reg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* Charger is OFF. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MAX77650_CHG_OFF 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Charger is in prequalification mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MAX77650_CHG_PREQ 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Charger is in fast-charge constant current mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MAX77650_CHG_ON_CURR 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /* Charger is in JEITA modified fast-charge constant-current mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define MAX77650_CHG_ON_CURR_JEITA 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* Charger is in fast-charge constant-voltage mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define MAX77650_CHG_ON_VOLT 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Charger is in JEITA modified fast-charge constant-voltage mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MAX77650_CHG_ON_VOLT_JEITA 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* Charger is in top-off mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MAX77650_CHG_ON_TOPOFF 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* Charger is in JEITA modified top-off mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define MAX77650_CHG_ON_TOPOFF_JEITA 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Charger is done. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define MAX77650_CHG_DONE 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Charger is JEITA modified done. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define MAX77650_CHG_DONE_JEITA 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Charger is suspended due to a prequalification timer fault. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Charger is suspended due to a fast-charge timer fault. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* Charger is suspended due to a battery temperature fault. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define MAX77650_CHGIN_DETAILS_BITS(_reg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define MAX77650_CHGIN_OKAY 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define MAX77650_CHARGER_CHG_MASK BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define MAX77650_CHARGER_CHG_CHARGING(_reg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct max77650_charger_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct regmap *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static enum power_supply_property max77650_charger_properties[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) POWER_SUPPLY_PROP_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) POWER_SUPPLY_PROP_ONLINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) POWER_SUPPLY_PROP_CHARGE_TYPE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static const unsigned int max77650_charger_vchgin_min_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) 4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static const unsigned int max77650_charger_ichgin_lim_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) 95000, 190000, 285000, 380000, 475000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int i, rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (val == max77650_charger_vchgin_min_table[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) rv = regmap_update_bits(chg->map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) MAX77650_REG_CNFG_CHG_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) MAX77650_CHARGER_VCHGIN_MIN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int i, rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (val == max77650_charger_ichgin_lim_table[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) rv = regmap_update_bits(chg->map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MAX77650_REG_CNFG_CHG_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) MAX77650_CHARGER_ICHGIN_LIM_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int max77650_charger_enable(struct max77650_charger_data *chg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) rv = regmap_update_bits(chg->map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) MAX77650_REG_CNFG_CHG_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) MAX77650_CHARGER_CHG_EN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) MAX77650_CHARGER_ENABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int max77650_charger_disable(struct max77650_charger_data *chg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) rv = regmap_update_bits(chg->map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) MAX77650_REG_CNFG_CHG_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) MAX77650_CHARGER_CHG_EN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) MAX77650_CHARGER_DISABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static irqreturn_t max77650_charger_check_status(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct max77650_charger_data *chg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int rv, reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (rv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) dev_err(chg->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) "unable to read the charger status: %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) max77650_charger_disable(chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) max77650_charger_disable(chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) case MAX77650_CHGIN_OKAY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) max77650_charger_enable(chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* May be 0x10 - debouncing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int max77650_charger_get_property(struct power_supply *psy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) enum power_supply_property psp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) union power_supply_propval *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int rv, reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) switch (psp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) case POWER_SUPPLY_PROP_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) val->intval = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) switch (MAX77650_CHG_DETAILS_BITS(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case MAX77650_CHG_OFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case MAX77650_CHG_PREQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case MAX77650_CHG_ON_CURR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case MAX77650_CHG_ON_CURR_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case MAX77650_CHG_ON_VOLT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) case MAX77650_CHG_ON_VOLT_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) case MAX77650_CHG_ON_TOPOFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) case MAX77650_CHG_ON_TOPOFF_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) val->intval = POWER_SUPPLY_STATUS_CHARGING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) case MAX77650_CHG_DONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) val->intval = POWER_SUPPLY_STATUS_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) case POWER_SUPPLY_PROP_ONLINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) case POWER_SUPPLY_PROP_CHARGE_TYPE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) switch (MAX77650_CHG_DETAILS_BITS(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case MAX77650_CHG_PREQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case MAX77650_CHG_ON_CURR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) case MAX77650_CHG_ON_CURR_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case MAX77650_CHG_ON_VOLT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) case MAX77650_CHG_ON_VOLT_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) case MAX77650_CHG_ON_TOPOFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) case MAX77650_CHG_ON_TOPOFF_JEITA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return 0;
^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) static const struct power_supply_desc max77650_battery_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .name = "max77650",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .type = POWER_SUPPLY_TYPE_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .get_property = max77650_charger_get_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .properties = max77650_charger_properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .num_properties = ARRAY_SIZE(max77650_charger_properties),
^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) static int max77650_charger_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) struct power_supply_config pscfg = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct max77650_charger_data *chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct power_supply *battery;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct device *dev, *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) int rv, chg_irq, chgin_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) unsigned int prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) parent = dev->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!chg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) platform_set_drvdata(pdev, chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) chg->map = dev_get_regmap(parent, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (!chg->map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) chg->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) pscfg.of_node = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) pscfg.drv_data = chg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) chg_irq = platform_get_irq_byname(pdev, "CHG");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (chg_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return chg_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (chgin_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return chgin_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) rv = devm_request_any_context_irq(dev, chg_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) max77650_charger_check_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) IRQF_ONESHOT, "chg", chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) rv = devm_request_any_context_irq(dev, chgin_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) max77650_charger_check_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) IRQF_ONESHOT, "chgin", chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) battery = devm_power_supply_register(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) &max77650_battery_desc, &pscfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (IS_ERR(battery))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return PTR_ERR(battery);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) rv = of_property_read_u32(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) "input-voltage-min-microvolt", &prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (rv == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) rv = max77650_charger_set_vchgin_min(chg, prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return rv;
^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) rv = of_property_read_u32(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) "input-current-limit-microamp", &prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (rv == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) rv = max77650_charger_set_ichgin_lim(chg, prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return max77650_charger_enable(chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static int max77650_charger_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct max77650_charger_data *chg = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return max77650_charger_disable(chg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static const struct of_device_id max77650_charger_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) { .compatible = "maxim,max77650-charger" },
^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) MODULE_DEVICE_TABLE(of, max77650_charger_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static struct platform_driver max77650_charger_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) .name = "max77650-charger",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .of_match_table = max77650_charger_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) .probe = max77650_charger_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .remove = max77650_charger_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) module_platform_driver(max77650_charger_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) MODULE_ALIAS("platform:max77650-charger");