15069185fSDan Murphy // SPDX-License-Identifier: GPL-2.0 25069185fSDan Murphy // BQ25980 Battery Charger Driver 35069185fSDan Murphy // Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ 45069185fSDan Murphy 55069185fSDan Murphy #include <linux/err.h> 65069185fSDan Murphy #include <linux/i2c.h> 75069185fSDan Murphy #include <linux/init.h> 85069185fSDan Murphy #include <linux/interrupt.h> 95069185fSDan Murphy #include <linux/kernel.h> 105069185fSDan Murphy #include <linux/module.h> 115069185fSDan Murphy #include <linux/gpio/consumer.h> 125069185fSDan Murphy #include <linux/power_supply.h> 135069185fSDan Murphy #include <linux/regmap.h> 145069185fSDan Murphy #include <linux/types.h> 155069185fSDan Murphy #include <linux/delay.h> 165069185fSDan Murphy #include <linux/device.h> 175069185fSDan Murphy #include <linux/moduleparam.h> 185069185fSDan Murphy #include <linux/slab.h> 195069185fSDan Murphy 205069185fSDan Murphy #include "bq25980_charger.h" 215069185fSDan Murphy 225069185fSDan Murphy struct bq25980_state { 235069185fSDan Murphy bool dischg; 245069185fSDan Murphy bool ovp; 255069185fSDan Murphy bool ocp; 265069185fSDan Murphy bool wdt; 275069185fSDan Murphy bool tflt; 285069185fSDan Murphy bool online; 295069185fSDan Murphy bool ce; 305069185fSDan Murphy bool hiz; 315069185fSDan Murphy bool bypass; 325069185fSDan Murphy 335069185fSDan Murphy u32 vbat_adc; 345069185fSDan Murphy u32 vsys_adc; 355069185fSDan Murphy u32 ibat_adc; 365069185fSDan Murphy }; 375069185fSDan Murphy 385069185fSDan Murphy enum bq25980_id { 395069185fSDan Murphy BQ25980, 405069185fSDan Murphy BQ25975, 415069185fSDan Murphy BQ25960, 425069185fSDan Murphy }; 435069185fSDan Murphy 445069185fSDan Murphy struct bq25980_chip_info { 455069185fSDan Murphy 465069185fSDan Murphy int model_id; 475069185fSDan Murphy 485069185fSDan Murphy const struct regmap_config *regmap_config; 495069185fSDan Murphy 505069185fSDan Murphy int busocp_def; 515069185fSDan Murphy int busocp_sc_max; 525069185fSDan Murphy int busocp_byp_max; 535069185fSDan Murphy int busocp_sc_min; 545069185fSDan Murphy int busocp_byp_min; 555069185fSDan Murphy 565069185fSDan Murphy int busovp_sc_def; 575069185fSDan Murphy int busovp_byp_def; 585069185fSDan Murphy int busovp_sc_step; 595069185fSDan Murphy 605069185fSDan Murphy int busovp_sc_offset; 615069185fSDan Murphy int busovp_byp_step; 625069185fSDan Murphy int busovp_byp_offset; 635069185fSDan Murphy int busovp_sc_min; 645069185fSDan Murphy int busovp_sc_max; 655069185fSDan Murphy int busovp_byp_min; 665069185fSDan Murphy int busovp_byp_max; 675069185fSDan Murphy 685069185fSDan Murphy int batovp_def; 695069185fSDan Murphy int batovp_max; 705069185fSDan Murphy int batovp_min; 715069185fSDan Murphy int batovp_step; 725069185fSDan Murphy int batovp_offset; 735069185fSDan Murphy 745069185fSDan Murphy int batocp_def; 755069185fSDan Murphy int batocp_max; 765069185fSDan Murphy }; 775069185fSDan Murphy 785069185fSDan Murphy struct bq25980_init_data { 795069185fSDan Murphy u32 ichg; 805069185fSDan Murphy u32 bypass_ilim; 815069185fSDan Murphy u32 sc_ilim; 825069185fSDan Murphy u32 vreg; 835069185fSDan Murphy u32 iterm; 845069185fSDan Murphy u32 iprechg; 855069185fSDan Murphy u32 bypass_vlim; 865069185fSDan Murphy u32 sc_vlim; 875069185fSDan Murphy u32 ichg_max; 885069185fSDan Murphy u32 vreg_max; 895069185fSDan Murphy }; 905069185fSDan Murphy 915069185fSDan Murphy struct bq25980_device { 925069185fSDan Murphy struct i2c_client *client; 935069185fSDan Murphy struct device *dev; 945069185fSDan Murphy struct power_supply *charger; 955069185fSDan Murphy struct power_supply *battery; 965069185fSDan Murphy struct mutex lock; 975069185fSDan Murphy struct regmap *regmap; 985069185fSDan Murphy 995069185fSDan Murphy char model_name[I2C_NAME_SIZE]; 1005069185fSDan Murphy 1015069185fSDan Murphy struct bq25980_init_data init_data; 1025069185fSDan Murphy const struct bq25980_chip_info *chip_info; 1035069185fSDan Murphy struct bq25980_state state; 1045069185fSDan Murphy int watchdog_timer; 1055069185fSDan Murphy }; 1065069185fSDan Murphy 1075069185fSDan Murphy static struct reg_default bq25980_reg_defs[] = { 1085069185fSDan Murphy {BQ25980_BATOVP, 0x5A}, 1095069185fSDan Murphy {BQ25980_BATOVP_ALM, 0x46}, 1105069185fSDan Murphy {BQ25980_BATOCP, 0x51}, 1115069185fSDan Murphy {BQ25980_BATOCP_ALM, 0x50}, 1125069185fSDan Murphy {BQ25980_BATUCP_ALM, 0x28}, 1135069185fSDan Murphy {BQ25980_CHRGR_CTRL_1, 0x0}, 1145069185fSDan Murphy {BQ25980_BUSOVP, 0x26}, 1155069185fSDan Murphy {BQ25980_BUSOVP_ALM, 0x22}, 1165069185fSDan Murphy {BQ25980_BUSOCP, 0xD}, 1175069185fSDan Murphy {BQ25980_BUSOCP_ALM, 0xC}, 1185069185fSDan Murphy {BQ25980_TEMP_CONTROL, 0x30}, 1195069185fSDan Murphy {BQ25980_TDIE_ALM, 0xC8}, 1205069185fSDan Murphy {BQ25980_TSBUS_FLT, 0x15}, 1215069185fSDan Murphy {BQ25980_TSBAT_FLG, 0x15}, 1225069185fSDan Murphy {BQ25980_VAC_CONTROL, 0x0}, 1235069185fSDan Murphy {BQ25980_CHRGR_CTRL_2, 0x0}, 1245069185fSDan Murphy {BQ25980_CHRGR_CTRL_3, 0x20}, 1255069185fSDan Murphy {BQ25980_CHRGR_CTRL_4, 0x1D}, 1265069185fSDan Murphy {BQ25980_CHRGR_CTRL_5, 0x18}, 1275069185fSDan Murphy {BQ25980_STAT1, 0x0}, 1285069185fSDan Murphy {BQ25980_STAT2, 0x0}, 1295069185fSDan Murphy {BQ25980_STAT3, 0x0}, 1305069185fSDan Murphy {BQ25980_STAT4, 0x0}, 1315069185fSDan Murphy {BQ25980_STAT5, 0x0}, 1325069185fSDan Murphy {BQ25980_FLAG1, 0x0}, 1335069185fSDan Murphy {BQ25980_FLAG2, 0x0}, 1345069185fSDan Murphy {BQ25980_FLAG3, 0x0}, 1355069185fSDan Murphy {BQ25980_FLAG4, 0x0}, 1365069185fSDan Murphy {BQ25980_FLAG5, 0x0}, 1375069185fSDan Murphy {BQ25980_MASK1, 0x0}, 1385069185fSDan Murphy {BQ25980_MASK2, 0x0}, 1395069185fSDan Murphy {BQ25980_MASK3, 0x0}, 1405069185fSDan Murphy {BQ25980_MASK4, 0x0}, 1415069185fSDan Murphy {BQ25980_MASK5, 0x0}, 1425069185fSDan Murphy {BQ25980_DEVICE_INFO, 0x8}, 1435069185fSDan Murphy {BQ25980_ADC_CONTROL1, 0x0}, 1445069185fSDan Murphy {BQ25980_ADC_CONTROL2, 0x0}, 1455069185fSDan Murphy {BQ25980_IBUS_ADC_LSB, 0x0}, 1465069185fSDan Murphy {BQ25980_IBUS_ADC_MSB, 0x0}, 1475069185fSDan Murphy {BQ25980_VBUS_ADC_LSB, 0x0}, 1485069185fSDan Murphy {BQ25980_VBUS_ADC_MSB, 0x0}, 1495069185fSDan Murphy {BQ25980_VAC1_ADC_LSB, 0x0}, 1505069185fSDan Murphy {BQ25980_VAC2_ADC_LSB, 0x0}, 1515069185fSDan Murphy {BQ25980_VOUT_ADC_LSB, 0x0}, 1525069185fSDan Murphy {BQ25980_VBAT_ADC_LSB, 0x0}, 1535069185fSDan Murphy {BQ25980_IBAT_ADC_MSB, 0x0}, 1545069185fSDan Murphy {BQ25980_IBAT_ADC_LSB, 0x0}, 1555069185fSDan Murphy {BQ25980_TSBUS_ADC_LSB, 0x0}, 1565069185fSDan Murphy {BQ25980_TSBAT_ADC_LSB, 0x0}, 1575069185fSDan Murphy {BQ25980_TDIE_ADC_LSB, 0x0}, 1585069185fSDan Murphy {BQ25980_DEGLITCH_TIME, 0x0}, 1595069185fSDan Murphy {BQ25980_CHRGR_CTRL_6, 0x0}, 1605069185fSDan Murphy }; 1615069185fSDan Murphy 1625069185fSDan Murphy static struct reg_default bq25975_reg_defs[] = { 1635069185fSDan Murphy {BQ25980_BATOVP, 0x5A}, 1645069185fSDan Murphy {BQ25980_BATOVP_ALM, 0x46}, 1655069185fSDan Murphy {BQ25980_BATOCP, 0x51}, 1665069185fSDan Murphy {BQ25980_BATOCP_ALM, 0x50}, 1675069185fSDan Murphy {BQ25980_BATUCP_ALM, 0x28}, 1685069185fSDan Murphy {BQ25980_CHRGR_CTRL_1, 0x0}, 1695069185fSDan Murphy {BQ25980_BUSOVP, 0x26}, 1705069185fSDan Murphy {BQ25980_BUSOVP_ALM, 0x22}, 1715069185fSDan Murphy {BQ25980_BUSOCP, 0xD}, 1725069185fSDan Murphy {BQ25980_BUSOCP_ALM, 0xC}, 1735069185fSDan Murphy {BQ25980_TEMP_CONTROL, 0x30}, 1745069185fSDan Murphy {BQ25980_TDIE_ALM, 0xC8}, 1755069185fSDan Murphy {BQ25980_TSBUS_FLT, 0x15}, 1765069185fSDan Murphy {BQ25980_TSBAT_FLG, 0x15}, 1775069185fSDan Murphy {BQ25980_VAC_CONTROL, 0x0}, 1785069185fSDan Murphy {BQ25980_CHRGR_CTRL_2, 0x0}, 1795069185fSDan Murphy {BQ25980_CHRGR_CTRL_3, 0x20}, 1805069185fSDan Murphy {BQ25980_CHRGR_CTRL_4, 0x1D}, 1815069185fSDan Murphy {BQ25980_CHRGR_CTRL_5, 0x18}, 1825069185fSDan Murphy {BQ25980_STAT1, 0x0}, 1835069185fSDan Murphy {BQ25980_STAT2, 0x0}, 1845069185fSDan Murphy {BQ25980_STAT3, 0x0}, 1855069185fSDan Murphy {BQ25980_STAT4, 0x0}, 1865069185fSDan Murphy {BQ25980_STAT5, 0x0}, 1875069185fSDan Murphy {BQ25980_FLAG1, 0x0}, 1885069185fSDan Murphy {BQ25980_FLAG2, 0x0}, 1895069185fSDan Murphy {BQ25980_FLAG3, 0x0}, 1905069185fSDan Murphy {BQ25980_FLAG4, 0x0}, 1915069185fSDan Murphy {BQ25980_FLAG5, 0x0}, 1925069185fSDan Murphy {BQ25980_MASK1, 0x0}, 1935069185fSDan Murphy {BQ25980_MASK2, 0x0}, 1945069185fSDan Murphy {BQ25980_MASK3, 0x0}, 1955069185fSDan Murphy {BQ25980_MASK4, 0x0}, 1965069185fSDan Murphy {BQ25980_MASK5, 0x0}, 1975069185fSDan Murphy {BQ25980_DEVICE_INFO, 0x8}, 1985069185fSDan Murphy {BQ25980_ADC_CONTROL1, 0x0}, 1995069185fSDan Murphy {BQ25980_ADC_CONTROL2, 0x0}, 2005069185fSDan Murphy {BQ25980_IBUS_ADC_LSB, 0x0}, 2015069185fSDan Murphy {BQ25980_IBUS_ADC_MSB, 0x0}, 2025069185fSDan Murphy {BQ25980_VBUS_ADC_LSB, 0x0}, 2035069185fSDan Murphy {BQ25980_VBUS_ADC_MSB, 0x0}, 2045069185fSDan Murphy {BQ25980_VAC1_ADC_LSB, 0x0}, 2055069185fSDan Murphy {BQ25980_VAC2_ADC_LSB, 0x0}, 2065069185fSDan Murphy {BQ25980_VOUT_ADC_LSB, 0x0}, 2075069185fSDan Murphy {BQ25980_VBAT_ADC_LSB, 0x0}, 2085069185fSDan Murphy {BQ25980_IBAT_ADC_MSB, 0x0}, 2095069185fSDan Murphy {BQ25980_IBAT_ADC_LSB, 0x0}, 2105069185fSDan Murphy {BQ25980_TSBUS_ADC_LSB, 0x0}, 2115069185fSDan Murphy {BQ25980_TSBAT_ADC_LSB, 0x0}, 2125069185fSDan Murphy {BQ25980_TDIE_ADC_LSB, 0x0}, 2135069185fSDan Murphy {BQ25980_DEGLITCH_TIME, 0x0}, 2145069185fSDan Murphy {BQ25980_CHRGR_CTRL_6, 0x0}, 2155069185fSDan Murphy }; 2165069185fSDan Murphy 2175069185fSDan Murphy static struct reg_default bq25960_reg_defs[] = { 2185069185fSDan Murphy {BQ25980_BATOVP, 0x5A}, 2195069185fSDan Murphy {BQ25980_BATOVP_ALM, 0x46}, 2205069185fSDan Murphy {BQ25980_BATOCP, 0x51}, 2215069185fSDan Murphy {BQ25980_BATOCP_ALM, 0x50}, 2225069185fSDan Murphy {BQ25980_BATUCP_ALM, 0x28}, 2235069185fSDan Murphy {BQ25980_CHRGR_CTRL_1, 0x0}, 2245069185fSDan Murphy {BQ25980_BUSOVP, 0x26}, 2255069185fSDan Murphy {BQ25980_BUSOVP_ALM, 0x22}, 2265069185fSDan Murphy {BQ25980_BUSOCP, 0xD}, 2275069185fSDan Murphy {BQ25980_BUSOCP_ALM, 0xC}, 2285069185fSDan Murphy {BQ25980_TEMP_CONTROL, 0x30}, 2295069185fSDan Murphy {BQ25980_TDIE_ALM, 0xC8}, 2305069185fSDan Murphy {BQ25980_TSBUS_FLT, 0x15}, 2315069185fSDan Murphy {BQ25980_TSBAT_FLG, 0x15}, 2325069185fSDan Murphy {BQ25980_VAC_CONTROL, 0x0}, 2335069185fSDan Murphy {BQ25980_CHRGR_CTRL_2, 0x0}, 2345069185fSDan Murphy {BQ25980_CHRGR_CTRL_3, 0x20}, 2355069185fSDan Murphy {BQ25980_CHRGR_CTRL_4, 0x1D}, 2365069185fSDan Murphy {BQ25980_CHRGR_CTRL_5, 0x18}, 2375069185fSDan Murphy {BQ25980_STAT1, 0x0}, 2385069185fSDan Murphy {BQ25980_STAT2, 0x0}, 2395069185fSDan Murphy {BQ25980_STAT3, 0x0}, 2405069185fSDan Murphy {BQ25980_STAT4, 0x0}, 2415069185fSDan Murphy {BQ25980_STAT5, 0x0}, 2425069185fSDan Murphy {BQ25980_FLAG1, 0x0}, 2435069185fSDan Murphy {BQ25980_FLAG2, 0x0}, 2445069185fSDan Murphy {BQ25980_FLAG3, 0x0}, 2455069185fSDan Murphy {BQ25980_FLAG4, 0x0}, 2465069185fSDan Murphy {BQ25980_FLAG5, 0x0}, 2475069185fSDan Murphy {BQ25980_MASK1, 0x0}, 2485069185fSDan Murphy {BQ25980_MASK2, 0x0}, 2495069185fSDan Murphy {BQ25980_MASK3, 0x0}, 2505069185fSDan Murphy {BQ25980_MASK4, 0x0}, 2515069185fSDan Murphy {BQ25980_MASK5, 0x0}, 2525069185fSDan Murphy {BQ25980_DEVICE_INFO, 0x8}, 2535069185fSDan Murphy {BQ25980_ADC_CONTROL1, 0x0}, 2545069185fSDan Murphy {BQ25980_ADC_CONTROL2, 0x0}, 2555069185fSDan Murphy {BQ25980_IBUS_ADC_LSB, 0x0}, 2565069185fSDan Murphy {BQ25980_IBUS_ADC_MSB, 0x0}, 2575069185fSDan Murphy {BQ25980_VBUS_ADC_LSB, 0x0}, 2585069185fSDan Murphy {BQ25980_VBUS_ADC_MSB, 0x0}, 2595069185fSDan Murphy {BQ25980_VAC1_ADC_LSB, 0x0}, 2605069185fSDan Murphy {BQ25980_VAC2_ADC_LSB, 0x0}, 2615069185fSDan Murphy {BQ25980_VOUT_ADC_LSB, 0x0}, 2625069185fSDan Murphy {BQ25980_VBAT_ADC_LSB, 0x0}, 2635069185fSDan Murphy {BQ25980_IBAT_ADC_MSB, 0x0}, 2645069185fSDan Murphy {BQ25980_IBAT_ADC_LSB, 0x0}, 2655069185fSDan Murphy {BQ25980_TSBUS_ADC_LSB, 0x0}, 2665069185fSDan Murphy {BQ25980_TSBAT_ADC_LSB, 0x0}, 2675069185fSDan Murphy {BQ25980_TDIE_ADC_LSB, 0x0}, 2685069185fSDan Murphy {BQ25980_DEGLITCH_TIME, 0x0}, 2695069185fSDan Murphy {BQ25980_CHRGR_CTRL_6, 0x0}, 2705069185fSDan Murphy }; 2715069185fSDan Murphy 2725069185fSDan Murphy static int bq25980_watchdog_time[BQ25980_NUM_WD_VAL] = {5000, 10000, 50000, 2735069185fSDan Murphy 300000}; 2745069185fSDan Murphy 2755069185fSDan Murphy static int bq25980_get_input_curr_lim(struct bq25980_device *bq) 2765069185fSDan Murphy { 2775069185fSDan Murphy unsigned int busocp_reg_code; 2785069185fSDan Murphy int ret; 2795069185fSDan Murphy 2805069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_BUSOCP, &busocp_reg_code); 2815069185fSDan Murphy if (ret) 2825069185fSDan Murphy return ret; 2835069185fSDan Murphy 2845069185fSDan Murphy return (busocp_reg_code * BQ25980_BUSOCP_STEP_uA) + BQ25980_BUSOCP_OFFSET_uA; 2855069185fSDan Murphy } 2865069185fSDan Murphy 2875069185fSDan Murphy static int bq25980_set_hiz(struct bq25980_device *bq, int setting) 2885069185fSDan Murphy { 2895069185fSDan Murphy return regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 2905069185fSDan Murphy BQ25980_EN_HIZ, setting); 2915069185fSDan Murphy } 2925069185fSDan Murphy 2935069185fSDan Murphy static int bq25980_set_input_curr_lim(struct bq25980_device *bq, int busocp) 2945069185fSDan Murphy { 2955069185fSDan Murphy unsigned int busocp_reg_code; 2965069185fSDan Murphy int ret; 2975069185fSDan Murphy 2985069185fSDan Murphy if (!busocp) 2995069185fSDan Murphy return bq25980_set_hiz(bq, BQ25980_ENABLE_HIZ); 3005069185fSDan Murphy 3015069185fSDan Murphy bq25980_set_hiz(bq, BQ25980_DISABLE_HIZ); 3025069185fSDan Murphy 3035069185fSDan Murphy if (busocp < BQ25980_BUSOCP_MIN_uA) 3045069185fSDan Murphy busocp = BQ25980_BUSOCP_MIN_uA; 3055069185fSDan Murphy 3065069185fSDan Murphy if (bq->state.bypass) 3075069185fSDan Murphy busocp = min(busocp, bq->chip_info->busocp_sc_max); 3085069185fSDan Murphy else 3095069185fSDan Murphy busocp = min(busocp, bq->chip_info->busocp_byp_max); 3105069185fSDan Murphy 3115069185fSDan Murphy busocp_reg_code = (busocp - BQ25980_BUSOCP_OFFSET_uA) 3125069185fSDan Murphy / BQ25980_BUSOCP_STEP_uA; 3135069185fSDan Murphy 3145069185fSDan Murphy ret = regmap_write(bq->regmap, BQ25980_BUSOCP, busocp_reg_code); 3155069185fSDan Murphy if (ret) 3165069185fSDan Murphy return ret; 3175069185fSDan Murphy 3185069185fSDan Murphy return regmap_write(bq->regmap, BQ25980_BUSOCP_ALM, busocp_reg_code); 3195069185fSDan Murphy } 3205069185fSDan Murphy 3215069185fSDan Murphy static int bq25980_get_input_volt_lim(struct bq25980_device *bq) 3225069185fSDan Murphy { 3235069185fSDan Murphy unsigned int busovp_reg_code; 3245069185fSDan Murphy unsigned int busovp_offset; 3255069185fSDan Murphy unsigned int busovp_step; 3265069185fSDan Murphy int ret; 3275069185fSDan Murphy 3285069185fSDan Murphy if (bq->state.bypass) { 3295069185fSDan Murphy busovp_step = bq->chip_info->busovp_byp_step; 3305069185fSDan Murphy busovp_offset = bq->chip_info->busovp_byp_offset; 3315069185fSDan Murphy } else { 3325069185fSDan Murphy busovp_step = bq->chip_info->busovp_sc_step; 3335069185fSDan Murphy busovp_offset = bq->chip_info->busovp_sc_offset; 3345069185fSDan Murphy } 3355069185fSDan Murphy 3365069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_BUSOVP, &busovp_reg_code); 3375069185fSDan Murphy if (ret) 3385069185fSDan Murphy return ret; 3395069185fSDan Murphy 3405069185fSDan Murphy return (busovp_reg_code * busovp_step) + busovp_offset; 3415069185fSDan Murphy } 3425069185fSDan Murphy 3435069185fSDan Murphy static int bq25980_set_input_volt_lim(struct bq25980_device *bq, int busovp) 3445069185fSDan Murphy { 3455069185fSDan Murphy unsigned int busovp_reg_code; 3465069185fSDan Murphy unsigned int busovp_step; 3475069185fSDan Murphy unsigned int busovp_offset; 3485069185fSDan Murphy int ret; 3495069185fSDan Murphy 3505069185fSDan Murphy if (bq->state.bypass) { 3515069185fSDan Murphy busovp_step = bq->chip_info->busovp_byp_step; 3525069185fSDan Murphy busovp_offset = bq->chip_info->busovp_byp_offset; 3535069185fSDan Murphy if (busovp > bq->chip_info->busovp_byp_max) 3545069185fSDan Murphy busovp = bq->chip_info->busovp_byp_max; 3555069185fSDan Murphy else if (busovp < bq->chip_info->busovp_byp_min) 3565069185fSDan Murphy busovp = bq->chip_info->busovp_byp_min; 3575069185fSDan Murphy } else { 3585069185fSDan Murphy busovp_step = bq->chip_info->busovp_sc_step; 3595069185fSDan Murphy busovp_offset = bq->chip_info->busovp_sc_offset; 3605069185fSDan Murphy if (busovp > bq->chip_info->busovp_sc_max) 3615069185fSDan Murphy busovp = bq->chip_info->busovp_sc_max; 3625069185fSDan Murphy else if (busovp < bq->chip_info->busovp_sc_min) 3635069185fSDan Murphy busovp = bq->chip_info->busovp_sc_min; 3645069185fSDan Murphy } 3655069185fSDan Murphy 3665069185fSDan Murphy busovp_reg_code = (busovp - busovp_offset) / busovp_step; 3675069185fSDan Murphy 3685069185fSDan Murphy ret = regmap_write(bq->regmap, BQ25980_BUSOVP, busovp_reg_code); 3695069185fSDan Murphy if (ret) 3705069185fSDan Murphy return ret; 3715069185fSDan Murphy 3725069185fSDan Murphy return regmap_write(bq->regmap, BQ25980_BUSOVP_ALM, busovp_reg_code); 3735069185fSDan Murphy } 3745069185fSDan Murphy 3755069185fSDan Murphy static int bq25980_get_const_charge_curr(struct bq25980_device *bq) 3765069185fSDan Murphy { 3775069185fSDan Murphy unsigned int batocp_reg_code; 3785069185fSDan Murphy int ret; 3795069185fSDan Murphy 3805069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_BATOCP, &batocp_reg_code); 3815069185fSDan Murphy if (ret) 3825069185fSDan Murphy return ret; 3835069185fSDan Murphy 3845069185fSDan Murphy return (batocp_reg_code & BQ25980_BATOCP_MASK) * 3855069185fSDan Murphy BQ25980_BATOCP_STEP_uA; 3865069185fSDan Murphy } 3875069185fSDan Murphy 3885069185fSDan Murphy static int bq25980_set_const_charge_curr(struct bq25980_device *bq, int batocp) 3895069185fSDan Murphy { 3905069185fSDan Murphy unsigned int batocp_reg_code; 3915069185fSDan Murphy int ret; 3925069185fSDan Murphy 3935069185fSDan Murphy batocp = max(batocp, BQ25980_BATOCP_MIN_uA); 3945069185fSDan Murphy batocp = min(batocp, bq->chip_info->batocp_max); 3955069185fSDan Murphy 3965069185fSDan Murphy batocp_reg_code = batocp / BQ25980_BATOCP_STEP_uA; 3975069185fSDan Murphy 3985069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_BATOCP, 3995069185fSDan Murphy BQ25980_BATOCP_MASK, batocp_reg_code); 4005069185fSDan Murphy if (ret) 4015069185fSDan Murphy return ret; 4025069185fSDan Murphy 4035069185fSDan Murphy return regmap_update_bits(bq->regmap, BQ25980_BATOCP_ALM, 4045069185fSDan Murphy BQ25980_BATOCP_MASK, batocp_reg_code); 4055069185fSDan Murphy } 4065069185fSDan Murphy 4075069185fSDan Murphy static int bq25980_get_const_charge_volt(struct bq25980_device *bq) 4085069185fSDan Murphy { 4095069185fSDan Murphy unsigned int batovp_reg_code; 4105069185fSDan Murphy int ret; 4115069185fSDan Murphy 4125069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_BATOVP, &batovp_reg_code); 4135069185fSDan Murphy if (ret) 4145069185fSDan Murphy return ret; 4155069185fSDan Murphy 4165069185fSDan Murphy return ((batovp_reg_code * bq->chip_info->batovp_step) + 4175069185fSDan Murphy bq->chip_info->batovp_offset); 4185069185fSDan Murphy } 4195069185fSDan Murphy 4205069185fSDan Murphy static int bq25980_set_const_charge_volt(struct bq25980_device *bq, int batovp) 4215069185fSDan Murphy { 4225069185fSDan Murphy unsigned int batovp_reg_code; 4235069185fSDan Murphy int ret; 4245069185fSDan Murphy 4255069185fSDan Murphy if (batovp < bq->chip_info->batovp_min) 4265069185fSDan Murphy batovp = bq->chip_info->batovp_min; 4275069185fSDan Murphy 4285069185fSDan Murphy if (batovp > bq->chip_info->batovp_max) 4295069185fSDan Murphy batovp = bq->chip_info->batovp_max; 4305069185fSDan Murphy 4315069185fSDan Murphy batovp_reg_code = (batovp - bq->chip_info->batovp_offset) / 4325069185fSDan Murphy bq->chip_info->batovp_step; 4335069185fSDan Murphy 4345069185fSDan Murphy ret = regmap_write(bq->regmap, BQ25980_BATOVP, batovp_reg_code); 4355069185fSDan Murphy if (ret) 4365069185fSDan Murphy return ret; 4375069185fSDan Murphy 4385069185fSDan Murphy return regmap_write(bq->regmap, BQ25980_BATOVP_ALM, batovp_reg_code); 4395069185fSDan Murphy } 4405069185fSDan Murphy 4415069185fSDan Murphy static int bq25980_set_bypass(struct bq25980_device *bq, bool en_bypass) 4425069185fSDan Murphy { 4435069185fSDan Murphy int ret; 4445069185fSDan Murphy 4455069185fSDan Murphy if (en_bypass) 4465069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 4475069185fSDan Murphy BQ25980_EN_BYPASS, BQ25980_EN_BYPASS); 4485069185fSDan Murphy else 4495069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 4505069185fSDan Murphy BQ25980_EN_BYPASS, en_bypass); 4515069185fSDan Murphy if (ret) 4525069185fSDan Murphy return ret; 4535069185fSDan Murphy 4545069185fSDan Murphy bq->state.bypass = en_bypass; 4555069185fSDan Murphy 4565069185fSDan Murphy return bq->state.bypass; 4575069185fSDan Murphy } 4585069185fSDan Murphy 4595069185fSDan Murphy static int bq25980_set_chg_en(struct bq25980_device *bq, bool en_chg) 4605069185fSDan Murphy { 4615069185fSDan Murphy int ret; 4625069185fSDan Murphy 4635069185fSDan Murphy if (en_chg) 4645069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 4655069185fSDan Murphy BQ25980_CHG_EN, BQ25980_CHG_EN); 4665069185fSDan Murphy else 4675069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 4685069185fSDan Murphy BQ25980_CHG_EN, en_chg); 4695069185fSDan Murphy if (ret) 4705069185fSDan Murphy return ret; 4715069185fSDan Murphy 4725069185fSDan Murphy bq->state.ce = en_chg; 4735069185fSDan Murphy 4745069185fSDan Murphy return 0; 4755069185fSDan Murphy } 4765069185fSDan Murphy 4775069185fSDan Murphy static int bq25980_get_adc_ibus(struct bq25980_device *bq) 4785069185fSDan Murphy { 4795069185fSDan Murphy int ibus_adc_lsb, ibus_adc_msb; 4805069185fSDan Murphy u16 ibus_adc; 4815069185fSDan Murphy int ret; 4825069185fSDan Murphy 4835069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_IBUS_ADC_MSB, &ibus_adc_msb); 4845069185fSDan Murphy if (ret) 4855069185fSDan Murphy return ret; 4865069185fSDan Murphy 4875069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_IBUS_ADC_LSB, &ibus_adc_lsb); 4885069185fSDan Murphy if (ret) 4895069185fSDan Murphy return ret; 4905069185fSDan Murphy 4915069185fSDan Murphy ibus_adc = (ibus_adc_msb << 8) | ibus_adc_lsb; 4925069185fSDan Murphy 4935069185fSDan Murphy if (ibus_adc_msb & BQ25980_ADC_POLARITY_BIT) 4945069185fSDan Murphy return ((ibus_adc ^ 0xffff) + 1) * BQ25980_ADC_CURR_STEP_uA; 4955069185fSDan Murphy 4965069185fSDan Murphy return ibus_adc * BQ25980_ADC_CURR_STEP_uA; 4975069185fSDan Murphy } 4985069185fSDan Murphy 4995069185fSDan Murphy static int bq25980_get_adc_vbus(struct bq25980_device *bq) 5005069185fSDan Murphy { 5015069185fSDan Murphy int vbus_adc_lsb, vbus_adc_msb; 5025069185fSDan Murphy u16 vbus_adc; 5035069185fSDan Murphy int ret; 5045069185fSDan Murphy 5055069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_VBUS_ADC_MSB, &vbus_adc_msb); 5065069185fSDan Murphy if (ret) 5075069185fSDan Murphy return ret; 5085069185fSDan Murphy 5095069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_VBUS_ADC_LSB, &vbus_adc_lsb); 5105069185fSDan Murphy if (ret) 5115069185fSDan Murphy return ret; 5125069185fSDan Murphy 5135069185fSDan Murphy vbus_adc = (vbus_adc_msb << 8) | vbus_adc_lsb; 5145069185fSDan Murphy 5155069185fSDan Murphy return vbus_adc * BQ25980_ADC_VOLT_STEP_uV; 5165069185fSDan Murphy } 5175069185fSDan Murphy 5185069185fSDan Murphy static int bq25980_get_ibat_adc(struct bq25980_device *bq) 5195069185fSDan Murphy { 5205069185fSDan Murphy int ret; 5215069185fSDan Murphy int ibat_adc_lsb, ibat_adc_msb; 5225069185fSDan Murphy int ibat_adc; 5235069185fSDan Murphy 5245069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_MSB, &ibat_adc_msb); 5255069185fSDan Murphy if (ret) 5265069185fSDan Murphy return ret; 5275069185fSDan Murphy 5285069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_LSB, &ibat_adc_lsb); 5295069185fSDan Murphy if (ret) 5305069185fSDan Murphy return ret; 5315069185fSDan Murphy 5325069185fSDan Murphy ibat_adc = (ibat_adc_msb << 8) | ibat_adc_lsb; 5335069185fSDan Murphy 5345069185fSDan Murphy if (ibat_adc_msb & BQ25980_ADC_POLARITY_BIT) 5355069185fSDan Murphy return ((ibat_adc ^ 0xffff) + 1) * BQ25980_ADC_CURR_STEP_uA; 5365069185fSDan Murphy 5375069185fSDan Murphy return ibat_adc * BQ25980_ADC_CURR_STEP_uA; 5385069185fSDan Murphy } 5395069185fSDan Murphy 5405069185fSDan Murphy static int bq25980_get_adc_vbat(struct bq25980_device *bq) 5415069185fSDan Murphy { 5425069185fSDan Murphy int vsys_adc_lsb, vsys_adc_msb; 5435069185fSDan Murphy u16 vsys_adc; 5445069185fSDan Murphy int ret; 5455069185fSDan Murphy 5465069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_VBAT_ADC_MSB, &vsys_adc_msb); 5475069185fSDan Murphy if (ret) 5485069185fSDan Murphy return ret; 5495069185fSDan Murphy 5505069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_VBAT_ADC_LSB, &vsys_adc_lsb); 5515069185fSDan Murphy if (ret) 5525069185fSDan Murphy return ret; 5535069185fSDan Murphy 5545069185fSDan Murphy vsys_adc = (vsys_adc_msb << 8) | vsys_adc_lsb; 5555069185fSDan Murphy 5565069185fSDan Murphy return vsys_adc * BQ25980_ADC_VOLT_STEP_uV; 5575069185fSDan Murphy } 5585069185fSDan Murphy 5595069185fSDan Murphy static int bq25980_get_state(struct bq25980_device *bq, 5605069185fSDan Murphy struct bq25980_state *state) 5615069185fSDan Murphy { 5625069185fSDan Murphy unsigned int chg_ctrl_2; 5635069185fSDan Murphy unsigned int stat1; 5645069185fSDan Murphy unsigned int stat2; 5655069185fSDan Murphy unsigned int stat3; 5665069185fSDan Murphy unsigned int stat4; 5675069185fSDan Murphy unsigned int ibat_adc_msb; 5685069185fSDan Murphy int ret; 5695069185fSDan Murphy 5705069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_STAT1, &stat1); 5715069185fSDan Murphy if (ret) 5725069185fSDan Murphy return ret; 5735069185fSDan Murphy 5745069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_STAT2, &stat2); 5755069185fSDan Murphy if (ret) 5765069185fSDan Murphy return ret; 5775069185fSDan Murphy 5785069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_STAT3, &stat3); 5795069185fSDan Murphy if (ret) 5805069185fSDan Murphy return ret; 5815069185fSDan Murphy 5825069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_STAT4, &stat4); 5835069185fSDan Murphy if (ret) 5845069185fSDan Murphy return ret; 5855069185fSDan Murphy 5865069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_CHRGR_CTRL_2, &chg_ctrl_2); 5875069185fSDan Murphy if (ret) 5885069185fSDan Murphy return ret; 5895069185fSDan Murphy 5905069185fSDan Murphy ret = regmap_read(bq->regmap, BQ25980_IBAT_ADC_MSB, &ibat_adc_msb); 5915069185fSDan Murphy if (ret) 5925069185fSDan Murphy return ret; 5935069185fSDan Murphy 5945069185fSDan Murphy state->dischg = ibat_adc_msb & BQ25980_ADC_POLARITY_BIT; 5955069185fSDan Murphy state->ovp = (stat1 & BQ25980_STAT1_OVP_MASK) | 5965069185fSDan Murphy (stat3 & BQ25980_STAT3_OVP_MASK); 5975069185fSDan Murphy state->ocp = (stat1 & BQ25980_STAT1_OCP_MASK) | 5985069185fSDan Murphy (stat2 & BQ25980_STAT2_OCP_MASK); 5995069185fSDan Murphy state->tflt = stat4 & BQ25980_STAT4_TFLT_MASK; 6005069185fSDan Murphy state->wdt = stat4 & BQ25980_WD_STAT; 6015069185fSDan Murphy state->online = stat3 & BQ25980_PRESENT_MASK; 6025069185fSDan Murphy state->ce = chg_ctrl_2 & BQ25980_CHG_EN; 6035069185fSDan Murphy state->hiz = chg_ctrl_2 & BQ25980_EN_HIZ; 6045069185fSDan Murphy state->bypass = chg_ctrl_2 & BQ25980_EN_BYPASS; 6055069185fSDan Murphy 6065069185fSDan Murphy return 0; 6075069185fSDan Murphy } 6085069185fSDan Murphy 6095069185fSDan Murphy static int bq25980_get_battery_property(struct power_supply *psy, 6105069185fSDan Murphy enum power_supply_property psp, 6115069185fSDan Murphy union power_supply_propval *val) 6125069185fSDan Murphy { 6135069185fSDan Murphy struct bq25980_device *bq = power_supply_get_drvdata(psy); 6145069185fSDan Murphy int ret = 0; 6155069185fSDan Murphy 6165069185fSDan Murphy switch (psp) { 6175069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 6185069185fSDan Murphy val->intval = bq->init_data.ichg_max; 6195069185fSDan Murphy break; 6205069185fSDan Murphy 6215069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 6225069185fSDan Murphy val->intval = bq->init_data.vreg_max; 6235069185fSDan Murphy break; 6245069185fSDan Murphy 6255069185fSDan Murphy case POWER_SUPPLY_PROP_CURRENT_NOW: 6265069185fSDan Murphy ret = bq25980_get_ibat_adc(bq); 6275069185fSDan Murphy val->intval = ret; 6285069185fSDan Murphy break; 6295069185fSDan Murphy 6305069185fSDan Murphy case POWER_SUPPLY_PROP_VOLTAGE_NOW: 6315069185fSDan Murphy ret = bq25980_get_adc_vbat(bq); 6325069185fSDan Murphy if (ret < 0) 6335069185fSDan Murphy return ret; 6345069185fSDan Murphy 6355069185fSDan Murphy val->intval = ret; 6365069185fSDan Murphy break; 6375069185fSDan Murphy 6385069185fSDan Murphy default: 6395069185fSDan Murphy return -EINVAL; 6405069185fSDan Murphy } 6415069185fSDan Murphy 6425069185fSDan Murphy return ret; 6435069185fSDan Murphy } 6445069185fSDan Murphy 6455069185fSDan Murphy static int bq25980_set_charger_property(struct power_supply *psy, 6465069185fSDan Murphy enum power_supply_property prop, 6475069185fSDan Murphy const union power_supply_propval *val) 6485069185fSDan Murphy { 6495069185fSDan Murphy struct bq25980_device *bq = power_supply_get_drvdata(psy); 6505069185fSDan Murphy int ret = -EINVAL; 6515069185fSDan Murphy 6525069185fSDan Murphy switch (prop) { 6535069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 6545069185fSDan Murphy ret = bq25980_set_input_curr_lim(bq, val->intval); 6555069185fSDan Murphy if (ret) 6565069185fSDan Murphy return ret; 6575069185fSDan Murphy break; 6585069185fSDan Murphy 6595069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 6605069185fSDan Murphy ret = bq25980_set_input_volt_lim(bq, val->intval); 6615069185fSDan Murphy if (ret) 6625069185fSDan Murphy return ret; 6635069185fSDan Murphy break; 6645069185fSDan Murphy 6655069185fSDan Murphy case POWER_SUPPLY_PROP_CHARGE_TYPE: 6665069185fSDan Murphy ret = bq25980_set_bypass(bq, val->intval); 6675069185fSDan Murphy if (ret) 6685069185fSDan Murphy return ret; 6695069185fSDan Murphy break; 6705069185fSDan Murphy 6715069185fSDan Murphy case POWER_SUPPLY_PROP_STATUS: 6725069185fSDan Murphy ret = bq25980_set_chg_en(bq, val->intval); 6735069185fSDan Murphy if (ret) 6745069185fSDan Murphy return ret; 6755069185fSDan Murphy break; 6765069185fSDan Murphy 67704722cecSRicardo Rivera-Matos case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 67804722cecSRicardo Rivera-Matos ret = bq25980_set_const_charge_curr(bq, val->intval); 67904722cecSRicardo Rivera-Matos if (ret) 68004722cecSRicardo Rivera-Matos return ret; 68104722cecSRicardo Rivera-Matos break; 68204722cecSRicardo Rivera-Matos 68304722cecSRicardo Rivera-Matos case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 68404722cecSRicardo Rivera-Matos ret = bq25980_set_const_charge_volt(bq, val->intval); 68504722cecSRicardo Rivera-Matos if (ret) 68604722cecSRicardo Rivera-Matos return ret; 68704722cecSRicardo Rivera-Matos break; 68804722cecSRicardo Rivera-Matos 6895069185fSDan Murphy default: 6905069185fSDan Murphy return -EINVAL; 6915069185fSDan Murphy } 6925069185fSDan Murphy 6935069185fSDan Murphy return ret; 6945069185fSDan Murphy } 6955069185fSDan Murphy 6965069185fSDan Murphy static int bq25980_get_charger_property(struct power_supply *psy, 6975069185fSDan Murphy enum power_supply_property psp, 6985069185fSDan Murphy union power_supply_propval *val) 6995069185fSDan Murphy { 7005069185fSDan Murphy struct bq25980_device *bq = power_supply_get_drvdata(psy); 7015069185fSDan Murphy struct bq25980_state state; 7025069185fSDan Murphy int ret = 0; 7035069185fSDan Murphy 7045069185fSDan Murphy mutex_lock(&bq->lock); 7055069185fSDan Murphy ret = bq25980_get_state(bq, &state); 7065069185fSDan Murphy mutex_unlock(&bq->lock); 7075069185fSDan Murphy if (ret) 7085069185fSDan Murphy return ret; 7095069185fSDan Murphy 7105069185fSDan Murphy switch (psp) { 7115069185fSDan Murphy case POWER_SUPPLY_PROP_MANUFACTURER: 7125069185fSDan Murphy val->strval = BQ25980_MANUFACTURER; 7135069185fSDan Murphy break; 7145069185fSDan Murphy case POWER_SUPPLY_PROP_MODEL_NAME: 7155069185fSDan Murphy val->strval = bq->model_name; 7165069185fSDan Murphy break; 7175069185fSDan Murphy case POWER_SUPPLY_PROP_ONLINE: 7185069185fSDan Murphy val->intval = state.online; 7195069185fSDan Murphy break; 7205069185fSDan Murphy 7215069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 7225069185fSDan Murphy ret = bq25980_get_input_volt_lim(bq); 7235069185fSDan Murphy if (ret < 0) 7245069185fSDan Murphy return ret; 7255069185fSDan Murphy val->intval = ret; 7265069185fSDan Murphy break; 7275069185fSDan Murphy 7285069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 7295069185fSDan Murphy ret = bq25980_get_input_curr_lim(bq); 7305069185fSDan Murphy if (ret < 0) 7315069185fSDan Murphy return ret; 7325069185fSDan Murphy 7335069185fSDan Murphy val->intval = ret; 7345069185fSDan Murphy break; 7355069185fSDan Murphy 7365069185fSDan Murphy case POWER_SUPPLY_PROP_HEALTH: 7375069185fSDan Murphy val->intval = POWER_SUPPLY_HEALTH_GOOD; 7385069185fSDan Murphy 7395069185fSDan Murphy if (state.tflt) 7405069185fSDan Murphy val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 7415069185fSDan Murphy else if (state.ovp) 7425069185fSDan Murphy val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 7435069185fSDan Murphy else if (state.ocp) 7445069185fSDan Murphy val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; 7455069185fSDan Murphy else if (state.wdt) 7465069185fSDan Murphy val->intval = 7475069185fSDan Murphy POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE; 7485069185fSDan Murphy break; 7495069185fSDan Murphy 7505069185fSDan Murphy case POWER_SUPPLY_PROP_STATUS: 7515069185fSDan Murphy val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 7525069185fSDan Murphy 7535069185fSDan Murphy if ((state.ce) && (!state.hiz)) 7545069185fSDan Murphy val->intval = POWER_SUPPLY_STATUS_CHARGING; 7555069185fSDan Murphy else if (state.dischg) 7565069185fSDan Murphy val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 7575069185fSDan Murphy else if (!state.ce) 7585069185fSDan Murphy val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 7595069185fSDan Murphy break; 7605069185fSDan Murphy 7615069185fSDan Murphy case POWER_SUPPLY_PROP_CHARGE_TYPE: 7625069185fSDan Murphy val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 7635069185fSDan Murphy 7645069185fSDan Murphy if (!state.ce) 7655069185fSDan Murphy val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 7665069185fSDan Murphy else if (state.bypass) 767*be5f08f0SRicardo Rivera-Matos val->intval = POWER_SUPPLY_CHARGE_TYPE_BYPASS; 7685069185fSDan Murphy else if (!state.bypass) 7695069185fSDan Murphy val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 7705069185fSDan Murphy break; 7715069185fSDan Murphy 7725069185fSDan Murphy case POWER_SUPPLY_PROP_CURRENT_NOW: 7735069185fSDan Murphy ret = bq25980_get_adc_ibus(bq); 7745069185fSDan Murphy if (ret < 0) 7755069185fSDan Murphy return ret; 7765069185fSDan Murphy 7775069185fSDan Murphy val->intval = ret; 7785069185fSDan Murphy break; 7795069185fSDan Murphy 7805069185fSDan Murphy case POWER_SUPPLY_PROP_VOLTAGE_NOW: 7815069185fSDan Murphy ret = bq25980_get_adc_vbus(bq); 7825069185fSDan Murphy if (ret < 0) 7835069185fSDan Murphy return ret; 7845069185fSDan Murphy 7855069185fSDan Murphy val->intval = ret; 7865069185fSDan Murphy break; 7875069185fSDan Murphy 7885069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 7895069185fSDan Murphy ret = bq25980_get_const_charge_curr(bq); 7905069185fSDan Murphy if (ret < 0) 7915069185fSDan Murphy return ret; 7925069185fSDan Murphy 7935069185fSDan Murphy val->intval = ret; 7945069185fSDan Murphy break; 7955069185fSDan Murphy 7965069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 7975069185fSDan Murphy ret = bq25980_get_const_charge_volt(bq); 7985069185fSDan Murphy if (ret < 0) 7995069185fSDan Murphy return ret; 8005069185fSDan Murphy 8015069185fSDan Murphy val->intval = ret; 8025069185fSDan Murphy break; 8035069185fSDan Murphy 8045069185fSDan Murphy default: 8055069185fSDan Murphy return -EINVAL; 8065069185fSDan Murphy } 8075069185fSDan Murphy 8085069185fSDan Murphy return ret; 8095069185fSDan Murphy } 8105069185fSDan Murphy 8115069185fSDan Murphy static bool bq25980_state_changed(struct bq25980_device *bq, 8125069185fSDan Murphy struct bq25980_state *new_state) 8135069185fSDan Murphy { 8145069185fSDan Murphy struct bq25980_state old_state; 8155069185fSDan Murphy 8165069185fSDan Murphy mutex_lock(&bq->lock); 8175069185fSDan Murphy old_state = bq->state; 8185069185fSDan Murphy mutex_unlock(&bq->lock); 8195069185fSDan Murphy 8205069185fSDan Murphy return (old_state.dischg != new_state->dischg || 8215069185fSDan Murphy old_state.ovp != new_state->ovp || 8225069185fSDan Murphy old_state.ocp != new_state->ocp || 8235069185fSDan Murphy old_state.online != new_state->online || 8245069185fSDan Murphy old_state.wdt != new_state->wdt || 8255069185fSDan Murphy old_state.tflt != new_state->tflt || 8265069185fSDan Murphy old_state.ce != new_state->ce || 8275069185fSDan Murphy old_state.hiz != new_state->hiz || 8285069185fSDan Murphy old_state.bypass != new_state->bypass); 8295069185fSDan Murphy } 8305069185fSDan Murphy 8315069185fSDan Murphy static irqreturn_t bq25980_irq_handler_thread(int irq, void *private) 8325069185fSDan Murphy { 8335069185fSDan Murphy struct bq25980_device *bq = private; 8345069185fSDan Murphy struct bq25980_state state; 8355069185fSDan Murphy int ret; 8365069185fSDan Murphy 8375069185fSDan Murphy ret = bq25980_get_state(bq, &state); 8385069185fSDan Murphy if (ret < 0) 8395069185fSDan Murphy goto irq_out; 8405069185fSDan Murphy 8415069185fSDan Murphy if (!bq25980_state_changed(bq, &state)) 8425069185fSDan Murphy goto irq_out; 8435069185fSDan Murphy 8445069185fSDan Murphy mutex_lock(&bq->lock); 8455069185fSDan Murphy bq->state = state; 8465069185fSDan Murphy mutex_unlock(&bq->lock); 8475069185fSDan Murphy 8485069185fSDan Murphy power_supply_changed(bq->charger); 8495069185fSDan Murphy 8505069185fSDan Murphy irq_out: 8515069185fSDan Murphy return IRQ_HANDLED; 8525069185fSDan Murphy } 8535069185fSDan Murphy 8545069185fSDan Murphy static enum power_supply_property bq25980_power_supply_props[] = { 8555069185fSDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 8565069185fSDan Murphy POWER_SUPPLY_PROP_MODEL_NAME, 8575069185fSDan Murphy POWER_SUPPLY_PROP_STATUS, 8585069185fSDan Murphy POWER_SUPPLY_PROP_ONLINE, 8595069185fSDan Murphy POWER_SUPPLY_PROP_HEALTH, 8605069185fSDan Murphy POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, 8615069185fSDan Murphy POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 8625069185fSDan Murphy POWER_SUPPLY_PROP_CHARGE_TYPE, 8635069185fSDan Murphy POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 8645069185fSDan Murphy POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 8655069185fSDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 8665069185fSDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 8675069185fSDan Murphy }; 8685069185fSDan Murphy 8695069185fSDan Murphy static enum power_supply_property bq25980_battery_props[] = { 8705069185fSDan Murphy POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 8715069185fSDan Murphy POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 8725069185fSDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 8735069185fSDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 8745069185fSDan Murphy }; 8755069185fSDan Murphy 8765069185fSDan Murphy static char *bq25980_charger_supplied_to[] = { 8775069185fSDan Murphy "main-battery", 8785069185fSDan Murphy }; 8795069185fSDan Murphy 8805069185fSDan Murphy static int bq25980_property_is_writeable(struct power_supply *psy, 8815069185fSDan Murphy enum power_supply_property prop) 8825069185fSDan Murphy { 8835069185fSDan Murphy switch (prop) { 8845069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 8855069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 8865069185fSDan Murphy case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 8875069185fSDan Murphy case POWER_SUPPLY_PROP_CHARGE_TYPE: 8885069185fSDan Murphy case POWER_SUPPLY_PROP_STATUS: 8895069185fSDan Murphy case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: 8905069185fSDan Murphy return true; 8915069185fSDan Murphy default: 8925069185fSDan Murphy return false; 8935069185fSDan Murphy } 8945069185fSDan Murphy } 8955069185fSDan Murphy 8965069185fSDan Murphy static const struct power_supply_desc bq25980_power_supply_desc = { 8975069185fSDan Murphy .name = "bq25980-charger", 8985069185fSDan Murphy .type = POWER_SUPPLY_TYPE_MAINS, 8995069185fSDan Murphy .properties = bq25980_power_supply_props, 9005069185fSDan Murphy .num_properties = ARRAY_SIZE(bq25980_power_supply_props), 9015069185fSDan Murphy .get_property = bq25980_get_charger_property, 9025069185fSDan Murphy .set_property = bq25980_set_charger_property, 9035069185fSDan Murphy .property_is_writeable = bq25980_property_is_writeable, 9045069185fSDan Murphy }; 9055069185fSDan Murphy 9065069185fSDan Murphy static struct power_supply_desc bq25980_battery_desc = { 9075069185fSDan Murphy .name = "bq25980-battery", 9085069185fSDan Murphy .type = POWER_SUPPLY_TYPE_BATTERY, 9095069185fSDan Murphy .get_property = bq25980_get_battery_property, 9105069185fSDan Murphy .properties = bq25980_battery_props, 9115069185fSDan Murphy .num_properties = ARRAY_SIZE(bq25980_battery_props), 9125069185fSDan Murphy .property_is_writeable = bq25980_property_is_writeable, 9135069185fSDan Murphy }; 9145069185fSDan Murphy 9155069185fSDan Murphy 9165069185fSDan Murphy static bool bq25980_is_volatile_reg(struct device *dev, unsigned int reg) 9175069185fSDan Murphy { 9185069185fSDan Murphy switch (reg) { 9195069185fSDan Murphy case BQ25980_CHRGR_CTRL_2: 9205069185fSDan Murphy case BQ25980_STAT1...BQ25980_FLAG5: 9215069185fSDan Murphy case BQ25980_ADC_CONTROL1...BQ25980_TDIE_ADC_LSB: 9225069185fSDan Murphy return true; 9235069185fSDan Murphy default: 9245069185fSDan Murphy return false; 9255069185fSDan Murphy } 9265069185fSDan Murphy } 9275069185fSDan Murphy 9285069185fSDan Murphy static const struct regmap_config bq25980_regmap_config = { 9295069185fSDan Murphy .reg_bits = 8, 9305069185fSDan Murphy .val_bits = 8, 9315069185fSDan Murphy 9325069185fSDan Murphy .max_register = BQ25980_CHRGR_CTRL_6, 9335069185fSDan Murphy .reg_defaults = bq25980_reg_defs, 9345069185fSDan Murphy .num_reg_defaults = ARRAY_SIZE(bq25980_reg_defs), 9355069185fSDan Murphy .cache_type = REGCACHE_RBTREE, 9365069185fSDan Murphy .volatile_reg = bq25980_is_volatile_reg, 9375069185fSDan Murphy }; 9385069185fSDan Murphy 9395069185fSDan Murphy static const struct regmap_config bq25975_regmap_config = { 9405069185fSDan Murphy .reg_bits = 8, 9415069185fSDan Murphy .val_bits = 8, 9425069185fSDan Murphy 9435069185fSDan Murphy .max_register = BQ25980_CHRGR_CTRL_6, 9445069185fSDan Murphy .reg_defaults = bq25975_reg_defs, 9455069185fSDan Murphy .num_reg_defaults = ARRAY_SIZE(bq25975_reg_defs), 9465069185fSDan Murphy .cache_type = REGCACHE_RBTREE, 9475069185fSDan Murphy .volatile_reg = bq25980_is_volatile_reg, 9485069185fSDan Murphy }; 9495069185fSDan Murphy 9505069185fSDan Murphy static const struct regmap_config bq25960_regmap_config = { 9515069185fSDan Murphy .reg_bits = 8, 9525069185fSDan Murphy .val_bits = 8, 9535069185fSDan Murphy 9545069185fSDan Murphy .max_register = BQ25980_CHRGR_CTRL_6, 9555069185fSDan Murphy .reg_defaults = bq25960_reg_defs, 9565069185fSDan Murphy .num_reg_defaults = ARRAY_SIZE(bq25960_reg_defs), 9575069185fSDan Murphy .cache_type = REGCACHE_RBTREE, 9585069185fSDan Murphy .volatile_reg = bq25980_is_volatile_reg, 9595069185fSDan Murphy }; 9605069185fSDan Murphy 9615069185fSDan Murphy static const struct bq25980_chip_info bq25980_chip_info_tbl[] = { 9625069185fSDan Murphy [BQ25980] = { 9635069185fSDan Murphy .model_id = BQ25980, 9645069185fSDan Murphy .regmap_config = &bq25980_regmap_config, 9655069185fSDan Murphy 9665069185fSDan Murphy .busocp_def = BQ25980_BUSOCP_DFLT_uA, 9675069185fSDan Murphy .busocp_sc_min = BQ25960_BUSOCP_SC_MAX_uA, 9685069185fSDan Murphy .busocp_sc_max = BQ25980_BUSOCP_SC_MAX_uA, 9695069185fSDan Murphy .busocp_byp_max = BQ25980_BUSOCP_BYP_MAX_uA, 9705069185fSDan Murphy .busocp_byp_min = BQ25980_BUSOCP_MIN_uA, 9715069185fSDan Murphy 9725069185fSDan Murphy .busovp_sc_def = BQ25980_BUSOVP_DFLT_uV, 9735069185fSDan Murphy .busovp_byp_def = BQ25980_BUSOVP_BYPASS_DFLT_uV, 9745069185fSDan Murphy .busovp_sc_step = BQ25980_BUSOVP_SC_STEP_uV, 9755069185fSDan Murphy .busovp_sc_offset = BQ25980_BUSOVP_SC_OFFSET_uV, 9765069185fSDan Murphy .busovp_byp_step = BQ25980_BUSOVP_BYP_STEP_uV, 9775069185fSDan Murphy .busovp_byp_offset = BQ25980_BUSOVP_BYP_OFFSET_uV, 9785069185fSDan Murphy .busovp_sc_min = BQ25980_BUSOVP_SC_MIN_uV, 9795069185fSDan Murphy .busovp_sc_max = BQ25980_BUSOVP_SC_MAX_uV, 9805069185fSDan Murphy .busovp_byp_min = BQ25980_BUSOVP_BYP_MIN_uV, 9815069185fSDan Murphy .busovp_byp_max = BQ25980_BUSOVP_BYP_MAX_uV, 9825069185fSDan Murphy 9835069185fSDan Murphy .batovp_def = BQ25980_BATOVP_DFLT_uV, 9845069185fSDan Murphy .batovp_max = BQ25980_BATOVP_MAX_uV, 9855069185fSDan Murphy .batovp_min = BQ25980_BATOVP_MIN_uV, 9865069185fSDan Murphy .batovp_step = BQ25980_BATOVP_STEP_uV, 9875069185fSDan Murphy .batovp_offset = BQ25980_BATOVP_OFFSET_uV, 9885069185fSDan Murphy 9895069185fSDan Murphy .batocp_def = BQ25980_BATOCP_DFLT_uA, 9905069185fSDan Murphy .batocp_max = BQ25980_BATOCP_MAX_uA, 9915069185fSDan Murphy }, 9925069185fSDan Murphy 9935069185fSDan Murphy [BQ25975] = { 9945069185fSDan Murphy .model_id = BQ25975, 9955069185fSDan Murphy .regmap_config = &bq25975_regmap_config, 9965069185fSDan Murphy 9975069185fSDan Murphy .busocp_def = BQ25975_BUSOCP_DFLT_uA, 9985069185fSDan Murphy .busocp_sc_min = BQ25975_BUSOCP_SC_MAX_uA, 9995069185fSDan Murphy .busocp_sc_max = BQ25975_BUSOCP_SC_MAX_uA, 10005069185fSDan Murphy .busocp_byp_min = BQ25980_BUSOCP_MIN_uA, 10015069185fSDan Murphy .busocp_byp_max = BQ25975_BUSOCP_BYP_MAX_uA, 10025069185fSDan Murphy 10035069185fSDan Murphy .busovp_sc_def = BQ25975_BUSOVP_DFLT_uV, 10045069185fSDan Murphy .busovp_byp_def = BQ25975_BUSOVP_BYPASS_DFLT_uV, 10055069185fSDan Murphy .busovp_sc_step = BQ25975_BUSOVP_SC_STEP_uV, 10065069185fSDan Murphy .busovp_sc_offset = BQ25975_BUSOVP_SC_OFFSET_uV, 10075069185fSDan Murphy .busovp_byp_step = BQ25975_BUSOVP_BYP_STEP_uV, 10085069185fSDan Murphy .busovp_byp_offset = BQ25975_BUSOVP_BYP_OFFSET_uV, 10095069185fSDan Murphy .busovp_sc_min = BQ25975_BUSOVP_SC_MIN_uV, 10105069185fSDan Murphy .busovp_sc_max = BQ25975_BUSOVP_SC_MAX_uV, 10115069185fSDan Murphy .busovp_byp_min = BQ25975_BUSOVP_BYP_MIN_uV, 10125069185fSDan Murphy .busovp_byp_max = BQ25975_BUSOVP_BYP_MAX_uV, 10135069185fSDan Murphy 10145069185fSDan Murphy .batovp_def = BQ25975_BATOVP_DFLT_uV, 10155069185fSDan Murphy .batovp_max = BQ25975_BATOVP_MAX_uV, 10165069185fSDan Murphy .batovp_min = BQ25975_BATOVP_MIN_uV, 10175069185fSDan Murphy .batovp_step = BQ25975_BATOVP_STEP_uV, 10185069185fSDan Murphy .batovp_offset = BQ25975_BATOVP_OFFSET_uV, 10195069185fSDan Murphy 10205069185fSDan Murphy .batocp_def = BQ25980_BATOCP_DFLT_uA, 10215069185fSDan Murphy .batocp_max = BQ25980_BATOCP_MAX_uA, 10225069185fSDan Murphy }, 10235069185fSDan Murphy 10245069185fSDan Murphy [BQ25960] = { 10255069185fSDan Murphy .model_id = BQ25960, 10265069185fSDan Murphy .regmap_config = &bq25960_regmap_config, 10275069185fSDan Murphy 10285069185fSDan Murphy .busocp_def = BQ25960_BUSOCP_DFLT_uA, 10295069185fSDan Murphy .busocp_sc_min = BQ25960_BUSOCP_SC_MAX_uA, 10305069185fSDan Murphy .busocp_sc_max = BQ25960_BUSOCP_SC_MAX_uA, 10315069185fSDan Murphy .busocp_byp_min = BQ25960_BUSOCP_SC_MAX_uA, 10325069185fSDan Murphy .busocp_byp_max = BQ25960_BUSOCP_BYP_MAX_uA, 10335069185fSDan Murphy 10345069185fSDan Murphy .busovp_sc_def = BQ25975_BUSOVP_DFLT_uV, 10355069185fSDan Murphy .busovp_byp_def = BQ25975_BUSOVP_BYPASS_DFLT_uV, 10365069185fSDan Murphy .busovp_sc_step = BQ25960_BUSOVP_SC_STEP_uV, 10375069185fSDan Murphy .busovp_sc_offset = BQ25960_BUSOVP_SC_OFFSET_uV, 10385069185fSDan Murphy .busovp_byp_step = BQ25960_BUSOVP_BYP_STEP_uV, 10395069185fSDan Murphy .busovp_byp_offset = BQ25960_BUSOVP_BYP_OFFSET_uV, 10405069185fSDan Murphy .busovp_sc_min = BQ25960_BUSOVP_SC_MIN_uV, 10415069185fSDan Murphy .busovp_sc_max = BQ25960_BUSOVP_SC_MAX_uV, 10425069185fSDan Murphy .busovp_byp_min = BQ25960_BUSOVP_BYP_MIN_uV, 10435069185fSDan Murphy .busovp_byp_max = BQ25960_BUSOVP_BYP_MAX_uV, 10445069185fSDan Murphy 10455069185fSDan Murphy .batovp_def = BQ25960_BATOVP_DFLT_uV, 10465069185fSDan Murphy .batovp_max = BQ25960_BATOVP_MAX_uV, 10475069185fSDan Murphy .batovp_min = BQ25960_BATOVP_MIN_uV, 10485069185fSDan Murphy .batovp_step = BQ25960_BATOVP_STEP_uV, 10495069185fSDan Murphy .batovp_offset = BQ25960_BATOVP_OFFSET_uV, 10505069185fSDan Murphy 10515069185fSDan Murphy .batocp_def = BQ25960_BATOCP_DFLT_uA, 10525069185fSDan Murphy .batocp_max = BQ25960_BATOCP_MAX_uA, 10535069185fSDan Murphy }, 10545069185fSDan Murphy }; 10555069185fSDan Murphy 10565069185fSDan Murphy static int bq25980_power_supply_init(struct bq25980_device *bq, 10575069185fSDan Murphy struct device *dev) 10585069185fSDan Murphy { 10595069185fSDan Murphy struct power_supply_config psy_cfg = { .drv_data = bq, 10605069185fSDan Murphy .of_node = dev->of_node, }; 10615069185fSDan Murphy 10625069185fSDan Murphy psy_cfg.supplied_to = bq25980_charger_supplied_to; 10635069185fSDan Murphy psy_cfg.num_supplicants = ARRAY_SIZE(bq25980_charger_supplied_to); 10645069185fSDan Murphy 10655069185fSDan Murphy bq->charger = devm_power_supply_register(bq->dev, 10665069185fSDan Murphy &bq25980_power_supply_desc, 10675069185fSDan Murphy &psy_cfg); 10685069185fSDan Murphy if (IS_ERR(bq->charger)) 10695069185fSDan Murphy return -EINVAL; 10705069185fSDan Murphy 10715069185fSDan Murphy bq->battery = devm_power_supply_register(bq->dev, 10725069185fSDan Murphy &bq25980_battery_desc, 10735069185fSDan Murphy &psy_cfg); 10745069185fSDan Murphy if (IS_ERR(bq->battery)) 10755069185fSDan Murphy return -EINVAL; 10765069185fSDan Murphy 10775069185fSDan Murphy return 0; 10785069185fSDan Murphy } 10795069185fSDan Murphy 10805069185fSDan Murphy static int bq25980_hw_init(struct bq25980_device *bq) 10815069185fSDan Murphy { 108225fd3303SLinus Walleij struct power_supply_battery_info *bat_info; 10836c59a17bSDan Murphy int wd_reg_val = BQ25980_WATCHDOG_DIS; 10846c59a17bSDan Murphy int wd_max_val = BQ25980_NUM_WD_VAL - 1; 10855069185fSDan Murphy int ret = 0; 10865069185fSDan Murphy int curr_val; 10875069185fSDan Murphy int volt_val; 10885069185fSDan Murphy int i; 10895069185fSDan Murphy 10906c59a17bSDan Murphy if (bq->watchdog_timer) { 10916c59a17bSDan Murphy if (bq->watchdog_timer >= bq25980_watchdog_time[wd_max_val]) 10926c59a17bSDan Murphy wd_reg_val = wd_max_val; 10936c59a17bSDan Murphy else { 10946c59a17bSDan Murphy for (i = 0; i < wd_max_val; i++) { 10955069185fSDan Murphy if (bq->watchdog_timer > bq25980_watchdog_time[i] && 10965069185fSDan Murphy bq->watchdog_timer < bq25980_watchdog_time[i + 1]) { 10975069185fSDan Murphy wd_reg_val = i; 10985069185fSDan Murphy break; 10995069185fSDan Murphy } 11005069185fSDan Murphy } 11016c59a17bSDan Murphy } 11026c59a17bSDan Murphy } 11035069185fSDan Murphy 11045069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_3, 11055069185fSDan Murphy BQ25980_WATCHDOG_MASK, wd_reg_val); 11065069185fSDan Murphy if (ret) 11075069185fSDan Murphy return ret; 11085069185fSDan Murphy 11095069185fSDan Murphy ret = power_supply_get_battery_info(bq->charger, &bat_info); 11105069185fSDan Murphy if (ret) { 11115069185fSDan Murphy dev_warn(bq->dev, "battery info missing\n"); 11125069185fSDan Murphy return -EINVAL; 11135069185fSDan Murphy } 11145069185fSDan Murphy 111525fd3303SLinus Walleij bq->init_data.ichg_max = bat_info->constant_charge_current_max_ua; 111625fd3303SLinus Walleij bq->init_data.vreg_max = bat_info->constant_charge_voltage_max_uv; 11175069185fSDan Murphy 11185069185fSDan Murphy if (bq->state.bypass) { 11195069185fSDan Murphy ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, 11205069185fSDan Murphy BQ25980_EN_BYPASS, BQ25980_EN_BYPASS); 11215069185fSDan Murphy if (ret) 11225069185fSDan Murphy return ret; 11235069185fSDan Murphy 11245069185fSDan Murphy curr_val = bq->init_data.bypass_ilim; 11255069185fSDan Murphy volt_val = bq->init_data.bypass_vlim; 11265069185fSDan Murphy } else { 11275069185fSDan Murphy curr_val = bq->init_data.sc_ilim; 11285069185fSDan Murphy volt_val = bq->init_data.sc_vlim; 11295069185fSDan Murphy } 11305069185fSDan Murphy 11315069185fSDan Murphy ret = bq25980_set_input_curr_lim(bq, curr_val); 11325069185fSDan Murphy if (ret) 11335069185fSDan Murphy return ret; 11345069185fSDan Murphy 11355069185fSDan Murphy ret = bq25980_set_input_volt_lim(bq, volt_val); 11365069185fSDan Murphy if (ret) 11375069185fSDan Murphy return ret; 11385069185fSDan Murphy 11395069185fSDan Murphy return regmap_update_bits(bq->regmap, BQ25980_ADC_CONTROL1, 11405069185fSDan Murphy BQ25980_ADC_EN, BQ25980_ADC_EN); 11415069185fSDan Murphy } 11425069185fSDan Murphy 11435069185fSDan Murphy static int bq25980_parse_dt(struct bq25980_device *bq) 11445069185fSDan Murphy { 11455069185fSDan Murphy int ret; 11465069185fSDan Murphy 11475069185fSDan Murphy ret = device_property_read_u32(bq->dev, "ti,watchdog-timeout-ms", 11485069185fSDan Murphy &bq->watchdog_timer); 11495069185fSDan Murphy if (ret) 11505069185fSDan Murphy bq->watchdog_timer = BQ25980_WATCHDOG_MIN; 11515069185fSDan Murphy 11525069185fSDan Murphy if (bq->watchdog_timer > BQ25980_WATCHDOG_MAX || 11535069185fSDan Murphy bq->watchdog_timer < BQ25980_WATCHDOG_MIN) 11545069185fSDan Murphy return -EINVAL; 11555069185fSDan Murphy 11565069185fSDan Murphy ret = device_property_read_u32(bq->dev, 11575069185fSDan Murphy "ti,sc-ovp-limit-microvolt", 11585069185fSDan Murphy &bq->init_data.sc_vlim); 11595069185fSDan Murphy if (ret) 11605069185fSDan Murphy bq->init_data.sc_vlim = bq->chip_info->busovp_sc_def; 11615069185fSDan Murphy 11625069185fSDan Murphy if (bq->init_data.sc_vlim > bq->chip_info->busovp_sc_max || 11635069185fSDan Murphy bq->init_data.sc_vlim < bq->chip_info->busovp_sc_min) { 11645069185fSDan Murphy dev_err(bq->dev, "SC ovp limit is out of range\n"); 11655069185fSDan Murphy return -EINVAL; 11665069185fSDan Murphy } 11675069185fSDan Murphy 11685069185fSDan Murphy ret = device_property_read_u32(bq->dev, 11695069185fSDan Murphy "ti,sc-ocp-limit-microamp", 11705069185fSDan Murphy &bq->init_data.sc_ilim); 11715069185fSDan Murphy if (ret) 11725069185fSDan Murphy bq->init_data.sc_ilim = bq->chip_info->busocp_def; 11735069185fSDan Murphy 11745069185fSDan Murphy if (bq->init_data.sc_ilim > bq->chip_info->busocp_sc_max || 11755069185fSDan Murphy bq->init_data.sc_ilim < bq->chip_info->busocp_sc_min) { 11765069185fSDan Murphy dev_err(bq->dev, "SC ocp limit is out of range\n"); 11775069185fSDan Murphy return -EINVAL; 11785069185fSDan Murphy } 11795069185fSDan Murphy 11805069185fSDan Murphy ret = device_property_read_u32(bq->dev, 11815069185fSDan Murphy "ti,bypass-ovp-limit-microvolt", 11825069185fSDan Murphy &bq->init_data.bypass_vlim); 11835069185fSDan Murphy if (ret) 11845069185fSDan Murphy bq->init_data.bypass_vlim = bq->chip_info->busovp_byp_def; 11855069185fSDan Murphy 11865069185fSDan Murphy if (bq->init_data.bypass_vlim > bq->chip_info->busovp_byp_max || 11875069185fSDan Murphy bq->init_data.bypass_vlim < bq->chip_info->busovp_byp_min) { 11885069185fSDan Murphy dev_err(bq->dev, "Bypass ovp limit is out of range\n"); 11895069185fSDan Murphy return -EINVAL; 11905069185fSDan Murphy } 11915069185fSDan Murphy 11925069185fSDan Murphy ret = device_property_read_u32(bq->dev, 11935069185fSDan Murphy "ti,bypass-ocp-limit-microamp", 11945069185fSDan Murphy &bq->init_data.bypass_ilim); 11955069185fSDan Murphy if (ret) 11965069185fSDan Murphy bq->init_data.bypass_ilim = bq->chip_info->busocp_def; 11975069185fSDan Murphy 11985069185fSDan Murphy if (bq->init_data.bypass_ilim > bq->chip_info->busocp_byp_max || 11995069185fSDan Murphy bq->init_data.bypass_ilim < bq->chip_info->busocp_byp_min) { 12005069185fSDan Murphy dev_err(bq->dev, "Bypass ocp limit is out of range\n"); 12015069185fSDan Murphy return -EINVAL; 12025069185fSDan Murphy } 12035069185fSDan Murphy 12045069185fSDan Murphy 12055069185fSDan Murphy bq->state.bypass = device_property_read_bool(bq->dev, 12065069185fSDan Murphy "ti,bypass-enable"); 12075069185fSDan Murphy return 0; 12085069185fSDan Murphy } 12095069185fSDan Murphy 12105069185fSDan Murphy static int bq25980_probe(struct i2c_client *client, 12115069185fSDan Murphy const struct i2c_device_id *id) 12125069185fSDan Murphy { 12135069185fSDan Murphy struct device *dev = &client->dev; 12145069185fSDan Murphy struct bq25980_device *bq; 12155069185fSDan Murphy int ret; 12165069185fSDan Murphy 12175069185fSDan Murphy bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); 12185069185fSDan Murphy if (!bq) 12195069185fSDan Murphy return -ENOMEM; 12205069185fSDan Murphy 12215069185fSDan Murphy bq->client = client; 12225069185fSDan Murphy bq->dev = dev; 12235069185fSDan Murphy 12245069185fSDan Murphy mutex_init(&bq->lock); 12255069185fSDan Murphy 12265069185fSDan Murphy strncpy(bq->model_name, id->name, I2C_NAME_SIZE); 12275069185fSDan Murphy bq->chip_info = &bq25980_chip_info_tbl[id->driver_data]; 12285069185fSDan Murphy 12295069185fSDan Murphy bq->regmap = devm_regmap_init_i2c(client, 12305069185fSDan Murphy bq->chip_info->regmap_config); 12315069185fSDan Murphy if (IS_ERR(bq->regmap)) { 12325069185fSDan Murphy dev_err(dev, "Failed to allocate register map\n"); 12335069185fSDan Murphy return PTR_ERR(bq->regmap); 12345069185fSDan Murphy } 12355069185fSDan Murphy 12365069185fSDan Murphy i2c_set_clientdata(client, bq); 12375069185fSDan Murphy 12385069185fSDan Murphy ret = bq25980_parse_dt(bq); 12395069185fSDan Murphy if (ret) { 12405069185fSDan Murphy dev_err(dev, "Failed to read device tree properties%d\n", ret); 12415069185fSDan Murphy return ret; 12425069185fSDan Murphy } 12435069185fSDan Murphy 12445069185fSDan Murphy if (client->irq) { 12455069185fSDan Murphy ret = devm_request_threaded_irq(dev, client->irq, NULL, 12465069185fSDan Murphy bq25980_irq_handler_thread, 12475069185fSDan Murphy IRQF_TRIGGER_FALLING | 12485069185fSDan Murphy IRQF_ONESHOT, 12495069185fSDan Murphy dev_name(&client->dev), bq); 12505069185fSDan Murphy if (ret) 12515069185fSDan Murphy return ret; 12525069185fSDan Murphy } 12535069185fSDan Murphy 12545069185fSDan Murphy ret = bq25980_power_supply_init(bq, dev); 12555069185fSDan Murphy if (ret) { 12565069185fSDan Murphy dev_err(dev, "Failed to register power supply\n"); 12575069185fSDan Murphy return ret; 12585069185fSDan Murphy } 12595069185fSDan Murphy 12605069185fSDan Murphy ret = bq25980_hw_init(bq); 12615069185fSDan Murphy if (ret) { 12625069185fSDan Murphy dev_err(dev, "Cannot initialize the chip.\n"); 12635069185fSDan Murphy return ret; 12645069185fSDan Murphy } 12655069185fSDan Murphy 12665069185fSDan Murphy return 0; 12675069185fSDan Murphy } 12685069185fSDan Murphy 12695069185fSDan Murphy static const struct i2c_device_id bq25980_i2c_ids[] = { 12705069185fSDan Murphy { "bq25980", BQ25980 }, 12715069185fSDan Murphy { "bq25975", BQ25975 }, 127279bcb02bSxinjian { "bq25960", BQ25960 }, 12735069185fSDan Murphy {}, 12745069185fSDan Murphy }; 12755069185fSDan Murphy MODULE_DEVICE_TABLE(i2c, bq25980_i2c_ids); 12765069185fSDan Murphy 12775069185fSDan Murphy static const struct of_device_id bq25980_of_match[] = { 12785069185fSDan Murphy { .compatible = "ti,bq25980", .data = (void *)BQ25980 }, 12795069185fSDan Murphy { .compatible = "ti,bq25975", .data = (void *)BQ25975 }, 12805069185fSDan Murphy { .compatible = "ti,bq25960", .data = (void *)BQ25960 }, 12815069185fSDan Murphy { }, 12825069185fSDan Murphy }; 12835069185fSDan Murphy MODULE_DEVICE_TABLE(of, bq25980_of_match); 12845069185fSDan Murphy 12855069185fSDan Murphy static struct i2c_driver bq25980_driver = { 12865069185fSDan Murphy .driver = { 12875069185fSDan Murphy .name = "bq25980-charger", 12885069185fSDan Murphy .of_match_table = bq25980_of_match, 12895069185fSDan Murphy }, 12905069185fSDan Murphy .probe = bq25980_probe, 12915069185fSDan Murphy .id_table = bq25980_i2c_ids, 12925069185fSDan Murphy }; 12935069185fSDan Murphy module_i2c_driver(bq25980_driver); 12945069185fSDan Murphy 12955069185fSDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 12965069185fSDan Murphy MODULE_AUTHOR("Ricardo Rivera-Matos <r-rivera-matos@ti.com>"); 12975069185fSDan Murphy MODULE_DESCRIPTION("bq25980 charger driver"); 12985069185fSDan Murphy MODULE_LICENSE("GPL v2"); 1299