1*b6f0796dSChiYuan Huang // SPDX-License-Identifier: GPL-2.0-only 2*b6f0796dSChiYuan Huang // 3*b6f0796dSChiYuan Huang // Copyright (C) 2025 Richtek Technology Corp. 4*b6f0796dSChiYuan Huang // 5*b6f0796dSChiYuan Huang // Authors: ChiYuan Huang <cy_huang@richtek.com> 6*b6f0796dSChiYuan Huang 7*b6f0796dSChiYuan Huang #include <linux/atomic.h> 8*b6f0796dSChiYuan Huang #include <linux/cleanup.h> 9*b6f0796dSChiYuan Huang #include <linux/i2c.h> 10*b6f0796dSChiYuan Huang #include <linux/kernel.h> 11*b6f0796dSChiYuan Huang #include <linux/linear_range.h> 12*b6f0796dSChiYuan Huang #include <linux/interrupt.h> 13*b6f0796dSChiYuan Huang #include <linux/mod_devicetable.h> 14*b6f0796dSChiYuan Huang #include <linux/module.h> 15*b6f0796dSChiYuan Huang #include <linux/mutex.h> 16*b6f0796dSChiYuan Huang #include <linux/power_supply.h> 17*b6f0796dSChiYuan Huang #include <linux/property.h> 18*b6f0796dSChiYuan Huang #include <linux/regmap.h> 19*b6f0796dSChiYuan Huang #include <linux/sysfs.h> 20*b6f0796dSChiYuan Huang #include <linux/util_macros.h> 21*b6f0796dSChiYuan Huang 22*b6f0796dSChiYuan Huang #define RT9756_REG_INTFLAG1 0x0B 23*b6f0796dSChiYuan Huang #define RT9756_REG_INTFLAG2 0x0D 24*b6f0796dSChiYuan Huang #define RT9756_REG_INTFLAG3 0x0F 25*b6f0796dSChiYuan Huang #define RT9756_REG_ADCCTL 0x11 26*b6f0796dSChiYuan Huang #define RT9756_REG_VBUSADC 0x12 27*b6f0796dSChiYuan Huang #define RT9756_REG_BC12FLAG 0x45 28*b6f0796dSChiYuan Huang #define RT9756_REG_INTFLAG4 0x49 29*b6f0796dSChiYuan Huang 30*b6f0796dSChiYuan Huang /* Flag1 */ 31*b6f0796dSChiYuan Huang #define RT9756_EVT_BUSOVP BIT(3) 32*b6f0796dSChiYuan Huang #define RT9756_EVT_BUSOCP BIT(2) 33*b6f0796dSChiYuan Huang #define RT9756_EVT_BUSUCP BIT(0) 34*b6f0796dSChiYuan Huang /* Flag2 */ 35*b6f0796dSChiYuan Huang #define RT9756_EVT_BATOVP BIT(7) 36*b6f0796dSChiYuan Huang #define RT9756_EVT_BATOCP BIT(6) 37*b6f0796dSChiYuan Huang #define RT9756_EVT_TDIEOTP BIT(3) 38*b6f0796dSChiYuan Huang #define RT9756_EVT_VBUSLOW_ERR BIT(2) 39*b6f0796dSChiYuan Huang #define RT9756_EVT_VAC_INSERT BIT(0) 40*b6f0796dSChiYuan Huang /* Flag3 */ 41*b6f0796dSChiYuan Huang #define RT9756_EVT_WDT BIT(5) 42*b6f0796dSChiYuan Huang #define RT9756_EVT_VAC_UVLO BIT(4) 43*b6f0796dSChiYuan Huang /* ADCCTL */ 44*b6f0796dSChiYuan Huang #define RT9756_ADCEN_MASK BIT(7) 45*b6f0796dSChiYuan Huang #define RT9756_ADCONCE_MASK BIT(6) 46*b6f0796dSChiYuan Huang /* Bc12_flag */ 47*b6f0796dSChiYuan Huang #define RT9756_EVT_BC12_DONE BIT(3) 48*b6f0796dSChiYuan Huang /* Flag4 */ 49*b6f0796dSChiYuan Huang #define RT9756_EVT_OUTOVP BIT(0) 50*b6f0796dSChiYuan Huang 51*b6f0796dSChiYuan Huang #define RICHTEK_DEVID 7 52*b6f0796dSChiYuan Huang #define RT9756_REVID 0 53*b6f0796dSChiYuan Huang #define RT9756A_REVID 1 54*b6f0796dSChiYuan Huang #define RT9757_REVID 2 55*b6f0796dSChiYuan Huang #define RT9757A_REVID 3 56*b6f0796dSChiYuan Huang #define RT9756_ADC_CONVTIME 1200 57*b6f0796dSChiYuan Huang #define RT9756_ADC_MAXWAIT 16000 58*b6f0796dSChiYuan Huang 59*b6f0796dSChiYuan Huang enum rt9756_model { 60*b6f0796dSChiYuan Huang MODEL_RT9756 = 0, 61*b6f0796dSChiYuan Huang MODEL_RT9757, 62*b6f0796dSChiYuan Huang MODEL_RT9770, 63*b6f0796dSChiYuan Huang MODEL_MAX 64*b6f0796dSChiYuan Huang }; 65*b6f0796dSChiYuan Huang 66*b6f0796dSChiYuan Huang enum rt9756_adc_chan { 67*b6f0796dSChiYuan Huang ADC_VBUS = 0, 68*b6f0796dSChiYuan Huang ADC_IBUS, 69*b6f0796dSChiYuan Huang ADC_VBAT, 70*b6f0796dSChiYuan Huang ADC_IBAT, 71*b6f0796dSChiYuan Huang ADC_TDIE, 72*b6f0796dSChiYuan Huang ADC_MAX_CHANNEL 73*b6f0796dSChiYuan Huang }; 74*b6f0796dSChiYuan Huang 75*b6f0796dSChiYuan Huang enum rt9756_usb_type { 76*b6f0796dSChiYuan Huang USB_NO_VBUS = 0, 77*b6f0796dSChiYuan Huang USB_SDP = 2, 78*b6f0796dSChiYuan Huang USB_NSTD, 79*b6f0796dSChiYuan Huang USB_DCP, 80*b6f0796dSChiYuan Huang USB_CDP, 81*b6f0796dSChiYuan Huang MAX_USB_TYPE 82*b6f0796dSChiYuan Huang }; 83*b6f0796dSChiYuan Huang 84*b6f0796dSChiYuan Huang enum rt9756_fields { 85*b6f0796dSChiYuan Huang F_VBATOVP = 0, 86*b6f0796dSChiYuan Huang F_VBATOVP_EN, 87*b6f0796dSChiYuan Huang F_IBATOCP, 88*b6f0796dSChiYuan Huang F_IBATOCP_EN, 89*b6f0796dSChiYuan Huang F_VBUSOVP, 90*b6f0796dSChiYuan Huang F_VBUSOVP_EN, 91*b6f0796dSChiYuan Huang F_IBUSOCP, 92*b6f0796dSChiYuan Huang F_IBUSOCP_EN, 93*b6f0796dSChiYuan Huang F_SWITCHING, 94*b6f0796dSChiYuan Huang F_REG_RST, 95*b6f0796dSChiYuan Huang F_CHG_EN, 96*b6f0796dSChiYuan Huang F_OP_MODE, 97*b6f0796dSChiYuan Huang F_WDT_DIS, 98*b6f0796dSChiYuan Huang F_WDT_TMR, 99*b6f0796dSChiYuan Huang F_DEV_ID, 100*b6f0796dSChiYuan Huang F_BC12_EN, 101*b6f0796dSChiYuan Huang F_USB_STATE, 102*b6f0796dSChiYuan Huang F_VBUS_STATE, 103*b6f0796dSChiYuan Huang F_IBAT_RSEN, 104*b6f0796dSChiYuan Huang F_REVISION, 105*b6f0796dSChiYuan Huang F_MAX_FIELD 106*b6f0796dSChiYuan Huang }; 107*b6f0796dSChiYuan Huang 108*b6f0796dSChiYuan Huang enum rt9756_ranges { 109*b6f0796dSChiYuan Huang R_VBATOVP = 0, 110*b6f0796dSChiYuan Huang R_IBATOCP, 111*b6f0796dSChiYuan Huang R_VBUSOVP, 112*b6f0796dSChiYuan Huang R_IBUSOCP, 113*b6f0796dSChiYuan Huang R_MAX_RANGE 114*b6f0796dSChiYuan Huang }; 115*b6f0796dSChiYuan Huang 116*b6f0796dSChiYuan Huang static const struct reg_field rt9756_chg_fields[F_MAX_FIELD] = { 117*b6f0796dSChiYuan Huang [F_VBATOVP] = REG_FIELD(0x08, 0, 4), 118*b6f0796dSChiYuan Huang [F_VBATOVP_EN] = REG_FIELD(0x08, 7, 7), 119*b6f0796dSChiYuan Huang [F_IBATOCP] = REG_FIELD(0x09, 0, 5), 120*b6f0796dSChiYuan Huang [F_IBATOCP_EN] = REG_FIELD(0x09, 7, 7), 121*b6f0796dSChiYuan Huang [F_VBUSOVP] = REG_FIELD(0x06, 0, 5), 122*b6f0796dSChiYuan Huang [F_VBUSOVP_EN] = REG_FIELD(0x06, 7, 7), 123*b6f0796dSChiYuan Huang [F_IBUSOCP] = REG_FIELD(0x07, 0, 4), 124*b6f0796dSChiYuan Huang [F_IBUSOCP_EN] = REG_FIELD(0x07, 5, 5), 125*b6f0796dSChiYuan Huang [F_SWITCHING] = REG_FIELD(0x5c, 7, 7), 126*b6f0796dSChiYuan Huang [F_REG_RST] = REG_FIELD(0x00, 7, 7), 127*b6f0796dSChiYuan Huang [F_CHG_EN] = REG_FIELD(0x00, 6, 6), 128*b6f0796dSChiYuan Huang [F_OP_MODE] = REG_FIELD(0x00, 5, 5), 129*b6f0796dSChiYuan Huang [F_WDT_DIS] = REG_FIELD(0x00, 3, 3), 130*b6f0796dSChiYuan Huang [F_WDT_TMR] = REG_FIELD(0x00, 0, 2), 131*b6f0796dSChiYuan Huang [F_DEV_ID] = REG_FIELD(0x03, 0, 3), 132*b6f0796dSChiYuan Huang [F_BC12_EN] = REG_FIELD(0x44, 7, 7), 133*b6f0796dSChiYuan Huang [F_USB_STATE] = REG_FIELD(0x46, 5, 7), 134*b6f0796dSChiYuan Huang [F_VBUS_STATE] = REG_FIELD(0x4c, 0, 0), 135*b6f0796dSChiYuan Huang [F_IBAT_RSEN] = REG_FIELD(0x5e, 0, 1), 136*b6f0796dSChiYuan Huang [F_REVISION] = REG_FIELD(0x62, 0, 1), 137*b6f0796dSChiYuan Huang }; 138*b6f0796dSChiYuan Huang 139*b6f0796dSChiYuan Huang static const struct reg_field rt9770_chg_fields[F_MAX_FIELD] = { 140*b6f0796dSChiYuan Huang [F_VBATOVP] = REG_FIELD(0x08, 0, 4), 141*b6f0796dSChiYuan Huang [F_VBATOVP_EN] = REG_FIELD(0x08, 7, 7), 142*b6f0796dSChiYuan Huang [F_IBATOCP] = REG_FIELD(0x09, 0, 5), 143*b6f0796dSChiYuan Huang [F_IBATOCP_EN] = REG_FIELD(0x09, 7, 7), 144*b6f0796dSChiYuan Huang [F_VBUSOVP] = REG_FIELD(0x06, 0, 5), 145*b6f0796dSChiYuan Huang [F_VBUSOVP_EN] = REG_FIELD(0x06, 7, 7), 146*b6f0796dSChiYuan Huang [F_IBUSOCP] = REG_FIELD(0x07, 0, 4), 147*b6f0796dSChiYuan Huang [F_IBUSOCP_EN] = REG_FIELD(0x07, 5, 5), 148*b6f0796dSChiYuan Huang [F_SWITCHING] = REG_FIELD(0x5c, 7, 7), 149*b6f0796dSChiYuan Huang [F_REG_RST] = REG_FIELD(0x00, 7, 7), 150*b6f0796dSChiYuan Huang [F_CHG_EN] = REG_FIELD(0x00, 6, 6), 151*b6f0796dSChiYuan Huang [F_OP_MODE] = REG_FIELD(0x00, 5, 5), 152*b6f0796dSChiYuan Huang [F_WDT_DIS] = REG_FIELD(0x00, 3, 3), 153*b6f0796dSChiYuan Huang [F_WDT_TMR] = REG_FIELD(0x00, 0, 2), 154*b6f0796dSChiYuan Huang [F_DEV_ID] = REG_FIELD(0x60, 0, 3), 155*b6f0796dSChiYuan Huang [F_BC12_EN] = REG_FIELD(0x03, 7, 7), 156*b6f0796dSChiYuan Huang [F_USB_STATE] = REG_FIELD(0x02, 5, 7), 157*b6f0796dSChiYuan Huang [F_VBUS_STATE] = REG_FIELD(0x4c, 0, 0), 158*b6f0796dSChiYuan Huang [F_IBAT_RSEN] = REG_FIELD(0x5e, 0, 1), 159*b6f0796dSChiYuan Huang [F_REVISION] = REG_FIELD(0x62, 3, 7), 160*b6f0796dSChiYuan Huang }; 161*b6f0796dSChiYuan Huang 162*b6f0796dSChiYuan Huang /* All converted to microvolt or microamp */ 163*b6f0796dSChiYuan Huang static const struct linear_range rt9756_chg_ranges[R_MAX_RANGE] = { 164*b6f0796dSChiYuan Huang LINEAR_RANGE_IDX(R_VBATOVP, 4200000, 0, 31, 25000), 165*b6f0796dSChiYuan Huang LINEAR_RANGE_IDX(R_IBATOCP, 2000000, 0, 63, 100000), 166*b6f0796dSChiYuan Huang LINEAR_RANGE_IDX(R_VBUSOVP, 3000000, 0, 63, 50000), 167*b6f0796dSChiYuan Huang LINEAR_RANGE_IDX(R_IBUSOCP, 1000000, 0, 31, 250000), 168*b6f0796dSChiYuan Huang }; 169*b6f0796dSChiYuan Huang 170*b6f0796dSChiYuan Huang struct charger_event { 171*b6f0796dSChiYuan Huang unsigned int flag1; 172*b6f0796dSChiYuan Huang unsigned int flag2; 173*b6f0796dSChiYuan Huang unsigned int flag3; 174*b6f0796dSChiYuan Huang unsigned int flag4; 175*b6f0796dSChiYuan Huang }; 176*b6f0796dSChiYuan Huang 177*b6f0796dSChiYuan Huang struct rt9756_data { 178*b6f0796dSChiYuan Huang struct device *dev; 179*b6f0796dSChiYuan Huang struct regmap *regmap; 180*b6f0796dSChiYuan Huang struct regmap_field *rm_fields[F_MAX_FIELD]; 181*b6f0796dSChiYuan Huang struct power_supply *psy; 182*b6f0796dSChiYuan Huang struct power_supply *bat_psy; 183*b6f0796dSChiYuan Huang struct mutex adc_lock; 184*b6f0796dSChiYuan Huang struct power_supply_desc psy_desc; 185*b6f0796dSChiYuan Huang struct power_supply_desc bat_psy_desc; 186*b6f0796dSChiYuan Huang struct charger_event chg_evt; 187*b6f0796dSChiYuan Huang unsigned int rg_resistor; 188*b6f0796dSChiYuan Huang unsigned int real_resistor; 189*b6f0796dSChiYuan Huang enum rt9756_model model; 190*b6f0796dSChiYuan Huang atomic_t usb_type; 191*b6f0796dSChiYuan Huang }; 192*b6f0796dSChiYuan Huang 193*b6f0796dSChiYuan Huang struct rt975x_dev_data { 194*b6f0796dSChiYuan Huang const struct regmap_config *regmap_config; 195*b6f0796dSChiYuan Huang const struct reg_field *reg_fields; 196*b6f0796dSChiYuan Huang const struct reg_sequence *init_regs; 197*b6f0796dSChiYuan Huang size_t num_init_regs; 198*b6f0796dSChiYuan Huang int (*check_device_model)(struct rt9756_data *data); 199*b6f0796dSChiYuan Huang }; 200*b6f0796dSChiYuan Huang 201*b6f0796dSChiYuan Huang static int rt9756_get_value_field_range(struct rt9756_data *data, enum rt9756_fields en_field, 202*b6f0796dSChiYuan Huang enum rt9756_fields field, enum rt9756_ranges rsel, int *val) 203*b6f0796dSChiYuan Huang { 204*b6f0796dSChiYuan Huang const struct linear_range *range = rt9756_chg_ranges + rsel; 205*b6f0796dSChiYuan Huang unsigned int enable, selector, value; 206*b6f0796dSChiYuan Huang int ret; 207*b6f0796dSChiYuan Huang 208*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[en_field], &enable); 209*b6f0796dSChiYuan Huang if (ret) 210*b6f0796dSChiYuan Huang return ret; 211*b6f0796dSChiYuan Huang 212*b6f0796dSChiYuan Huang if (!enable) { 213*b6f0796dSChiYuan Huang *val = 0; 214*b6f0796dSChiYuan Huang return 0; 215*b6f0796dSChiYuan Huang } 216*b6f0796dSChiYuan Huang 217*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[field], &selector); 218*b6f0796dSChiYuan Huang if (ret) 219*b6f0796dSChiYuan Huang return ret; 220*b6f0796dSChiYuan Huang 221*b6f0796dSChiYuan Huang ret = linear_range_get_value(range, selector, &value); 222*b6f0796dSChiYuan Huang if (ret) 223*b6f0796dSChiYuan Huang return ret; 224*b6f0796dSChiYuan Huang 225*b6f0796dSChiYuan Huang *val = (int)value; 226*b6f0796dSChiYuan Huang 227*b6f0796dSChiYuan Huang return 0; 228*b6f0796dSChiYuan Huang } 229*b6f0796dSChiYuan Huang 230*b6f0796dSChiYuan Huang static int rt9756_set_value_field_range(struct rt9756_data *data, enum rt9756_fields en_field, 231*b6f0796dSChiYuan Huang enum rt9756_fields field, enum rt9756_ranges rsel, int val) 232*b6f0796dSChiYuan Huang { 233*b6f0796dSChiYuan Huang const struct linear_range *range = rt9756_chg_ranges + rsel; 234*b6f0796dSChiYuan Huang unsigned int selector, value; 235*b6f0796dSChiYuan Huang int ret; 236*b6f0796dSChiYuan Huang 237*b6f0796dSChiYuan Huang if (!val) 238*b6f0796dSChiYuan Huang return regmap_field_write(data->rm_fields[en_field], 0); 239*b6f0796dSChiYuan Huang 240*b6f0796dSChiYuan Huang value = (unsigned int)val; 241*b6f0796dSChiYuan Huang linear_range_get_selector_within(range, value, &selector); 242*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[field], selector); 243*b6f0796dSChiYuan Huang if (ret) 244*b6f0796dSChiYuan Huang return ret; 245*b6f0796dSChiYuan Huang 246*b6f0796dSChiYuan Huang return regmap_field_write(data->rm_fields[en_field], 1); 247*b6f0796dSChiYuan Huang } 248*b6f0796dSChiYuan Huang 249*b6f0796dSChiYuan Huang static int rt9756_get_adc(struct rt9756_data *data, enum rt9756_adc_chan chan, 250*b6f0796dSChiYuan Huang int *val) 251*b6f0796dSChiYuan Huang { 252*b6f0796dSChiYuan Huang struct regmap *regmap = data->regmap; 253*b6f0796dSChiYuan Huang unsigned int reg_addr = RT9756_REG_VBUSADC + chan * 2; 254*b6f0796dSChiYuan Huang unsigned int mask = RT9756_ADCEN_MASK | RT9756_ADCONCE_MASK; 255*b6f0796dSChiYuan Huang unsigned int shift = 0, adc_cntl; 256*b6f0796dSChiYuan Huang __be16 raws; 257*b6f0796dSChiYuan Huang int scale, offset = 0, ret; 258*b6f0796dSChiYuan Huang 259*b6f0796dSChiYuan Huang guard(mutex)(&data->adc_lock); 260*b6f0796dSChiYuan Huang 261*b6f0796dSChiYuan Huang ret = regmap_update_bits(regmap, RT9756_REG_ADCCTL, mask, mask); 262*b6f0796dSChiYuan Huang if (ret) 263*b6f0796dSChiYuan Huang return ret; 264*b6f0796dSChiYuan Huang 265*b6f0796dSChiYuan Huang ret = regmap_read_poll_timeout(regmap, RT9756_REG_ADCCTL, adc_cntl, 266*b6f0796dSChiYuan Huang !(adc_cntl & RT9756_ADCEN_MASK), 267*b6f0796dSChiYuan Huang RT9756_ADC_CONVTIME, RT9756_ADC_MAXWAIT); 268*b6f0796dSChiYuan Huang if (ret && ret != -ETIMEDOUT) 269*b6f0796dSChiYuan Huang return ret; 270*b6f0796dSChiYuan Huang 271*b6f0796dSChiYuan Huang ret = regmap_raw_read(regmap, reg_addr, &raws, sizeof(raws)); 272*b6f0796dSChiYuan Huang if (ret) 273*b6f0796dSChiYuan Huang return ret; 274*b6f0796dSChiYuan Huang 275*b6f0796dSChiYuan Huang /* 276*b6f0796dSChiYuan Huang * TDIE LSB 1'c, others LSB 1000uV or 1000uA. 277*b6f0796dSChiYuan Huang * Rsense ratio is needed for IBAT channel 278*b6f0796dSChiYuan Huang */ 279*b6f0796dSChiYuan Huang if (chan == ADC_TDIE) { 280*b6f0796dSChiYuan Huang scale = 10; 281*b6f0796dSChiYuan Huang shift = 8; 282*b6f0796dSChiYuan Huang offset = -40; 283*b6f0796dSChiYuan Huang } else if (chan == ADC_IBAT) 284*b6f0796dSChiYuan Huang scale = 1000 * data->rg_resistor / data->real_resistor; 285*b6f0796dSChiYuan Huang else 286*b6f0796dSChiYuan Huang scale = 1000; 287*b6f0796dSChiYuan Huang 288*b6f0796dSChiYuan Huang *val = ((be16_to_cpu(raws) >> shift) + offset) * scale; 289*b6f0796dSChiYuan Huang 290*b6f0796dSChiYuan Huang return regmap_update_bits(regmap, RT9756_REG_ADCCTL, mask, 0); 291*b6f0796dSChiYuan Huang } 292*b6f0796dSChiYuan Huang 293*b6f0796dSChiYuan Huang static int rt9756_get_switching_state(struct rt9756_data *data, int *status) 294*b6f0796dSChiYuan Huang { 295*b6f0796dSChiYuan Huang unsigned int switching_state; 296*b6f0796dSChiYuan Huang int ret; 297*b6f0796dSChiYuan Huang 298*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_SWITCHING], &switching_state); 299*b6f0796dSChiYuan Huang if (ret) 300*b6f0796dSChiYuan Huang return ret; 301*b6f0796dSChiYuan Huang 302*b6f0796dSChiYuan Huang if (switching_state) 303*b6f0796dSChiYuan Huang *status = POWER_SUPPLY_STATUS_CHARGING; 304*b6f0796dSChiYuan Huang else 305*b6f0796dSChiYuan Huang *status = POWER_SUPPLY_STATUS_NOT_CHARGING; 306*b6f0796dSChiYuan Huang 307*b6f0796dSChiYuan Huang return 0; 308*b6f0796dSChiYuan Huang } 309*b6f0796dSChiYuan Huang 310*b6f0796dSChiYuan Huang static int rt9756_get_charger_health(struct rt9756_data *data) 311*b6f0796dSChiYuan Huang { 312*b6f0796dSChiYuan Huang struct charger_event *evt = &data->chg_evt; 313*b6f0796dSChiYuan Huang 314*b6f0796dSChiYuan Huang if (evt->flag2 & RT9756_EVT_VBUSLOW_ERR) 315*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_UNDERVOLTAGE; 316*b6f0796dSChiYuan Huang 317*b6f0796dSChiYuan Huang if (evt->flag1 & RT9756_EVT_BUSOVP || evt->flag2 & RT9756_EVT_BATOVP || 318*b6f0796dSChiYuan Huang evt->flag4 & RT9756_EVT_OUTOVP) 319*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_OVERVOLTAGE; 320*b6f0796dSChiYuan Huang 321*b6f0796dSChiYuan Huang if (evt->flag1 & RT9756_EVT_BUSOCP || evt->flag2 & RT9756_EVT_BATOCP) 322*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_OVERCURRENT; 323*b6f0796dSChiYuan Huang 324*b6f0796dSChiYuan Huang if (evt->flag1 & RT9756_EVT_BUSUCP) 325*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 326*b6f0796dSChiYuan Huang 327*b6f0796dSChiYuan Huang if (evt->flag2 & RT9756_EVT_TDIEOTP) 328*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_OVERHEAT; 329*b6f0796dSChiYuan Huang 330*b6f0796dSChiYuan Huang if (evt->flag3 & RT9756_EVT_WDT) 331*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE; 332*b6f0796dSChiYuan Huang 333*b6f0796dSChiYuan Huang return POWER_SUPPLY_HEALTH_GOOD; 334*b6f0796dSChiYuan Huang } 335*b6f0796dSChiYuan Huang 336*b6f0796dSChiYuan Huang static int rt9756_get_charger_online(struct rt9756_data *data, int *val) 337*b6f0796dSChiYuan Huang { 338*b6f0796dSChiYuan Huang unsigned int online; 339*b6f0796dSChiYuan Huang int ret; 340*b6f0796dSChiYuan Huang 341*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_VBUS_STATE], &online); 342*b6f0796dSChiYuan Huang if (ret) 343*b6f0796dSChiYuan Huang return ret; 344*b6f0796dSChiYuan Huang 345*b6f0796dSChiYuan Huang *val = !!online; 346*b6f0796dSChiYuan Huang return 0; 347*b6f0796dSChiYuan Huang } 348*b6f0796dSChiYuan Huang 349*b6f0796dSChiYuan Huang static int rt9756_get_vbus_ovp(struct rt9756_data *data, int *val) 350*b6f0796dSChiYuan Huang { 351*b6f0796dSChiYuan Huang unsigned int opmode; 352*b6f0796dSChiYuan Huang int ovpval, ret; 353*b6f0796dSChiYuan Huang 354*b6f0796dSChiYuan Huang /* operating mode -> 0 bypass, 1 div2 */ 355*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_OP_MODE], &opmode); 356*b6f0796dSChiYuan Huang if (ret) 357*b6f0796dSChiYuan Huang return ret; 358*b6f0796dSChiYuan Huang 359*b6f0796dSChiYuan Huang ret = rt9756_get_value_field_range(data, F_VBUSOVP_EN, F_VBUSOVP, R_VBUSOVP, &ovpval); 360*b6f0796dSChiYuan Huang if (ret) 361*b6f0796dSChiYuan Huang return ret; 362*b6f0796dSChiYuan Huang 363*b6f0796dSChiYuan Huang *val = opmode ? ovpval * 2 : ovpval; 364*b6f0796dSChiYuan Huang return 0; 365*b6f0796dSChiYuan Huang } 366*b6f0796dSChiYuan Huang 367*b6f0796dSChiYuan Huang static int rt9756_set_vbus_ovp(struct rt9756_data *data, int val) 368*b6f0796dSChiYuan Huang { 369*b6f0796dSChiYuan Huang unsigned int opmode; 370*b6f0796dSChiYuan Huang int ret; 371*b6f0796dSChiYuan Huang 372*b6f0796dSChiYuan Huang /* operating mode -> 0 bypass, 1 div2 */ 373*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_OP_MODE], &opmode); 374*b6f0796dSChiYuan Huang if (ret) 375*b6f0796dSChiYuan Huang return ret; 376*b6f0796dSChiYuan Huang 377*b6f0796dSChiYuan Huang return rt9756_set_value_field_range(data, F_VBUSOVP_EN, F_VBUSOVP, R_VBUSOVP, 378*b6f0796dSChiYuan Huang opmode ? val / 2 : val); 379*b6f0796dSChiYuan Huang } 380*b6f0796dSChiYuan Huang 381*b6f0796dSChiYuan Huang static const char * const rt9756_manufacturer = "Richtek Technology Corp."; 382*b6f0796dSChiYuan Huang static const char * const rt9756_model[MODEL_MAX] = { "RT9756", "RT9757", "RT9770" }; 383*b6f0796dSChiYuan Huang 384*b6f0796dSChiYuan Huang static int rt9756_psy_get_property(struct power_supply *psy, 385*b6f0796dSChiYuan Huang enum power_supply_property psp, 386*b6f0796dSChiYuan Huang union power_supply_propval *val) 387*b6f0796dSChiYuan Huang { 388*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 389*b6f0796dSChiYuan Huang int *pval = &val->intval; 390*b6f0796dSChiYuan Huang 391*b6f0796dSChiYuan Huang switch (psp) { 392*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_STATUS: 393*b6f0796dSChiYuan Huang return rt9756_get_switching_state(data, pval); 394*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_HEALTH: 395*b6f0796dSChiYuan Huang *pval = rt9756_get_charger_health(data); 396*b6f0796dSChiYuan Huang return 0; 397*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_ONLINE: 398*b6f0796dSChiYuan Huang return rt9756_get_charger_online(data, pval); 399*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_VOLTAGE_MAX: 400*b6f0796dSChiYuan Huang return rt9756_get_vbus_ovp(data, pval); 401*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_VOLTAGE_NOW: 402*b6f0796dSChiYuan Huang return rt9756_get_adc(data, ADC_VBUS, pval); 403*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CURRENT_MAX: 404*b6f0796dSChiYuan Huang return rt9756_get_value_field_range(data, F_IBUSOCP_EN, F_IBUSOCP, R_IBUSOCP, pval); 405*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CURRENT_NOW: 406*b6f0796dSChiYuan Huang return rt9756_get_adc(data, ADC_IBUS, pval); 407*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 408*b6f0796dSChiYuan Huang return rt9756_get_value_field_range(data, F_VBATOVP_EN, F_VBATOVP, R_VBATOVP, pval); 409*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 410*b6f0796dSChiYuan Huang return rt9756_get_value_field_range(data, F_IBATOCP_EN, F_IBATOCP, R_IBATOCP, pval); 411*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_TEMP: 412*b6f0796dSChiYuan Huang return rt9756_get_adc(data, ADC_TDIE, pval); 413*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_USB_TYPE: 414*b6f0796dSChiYuan Huang *pval = atomic_read(&data->usb_type); 415*b6f0796dSChiYuan Huang return 0; 416*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_MODEL_NAME: 417*b6f0796dSChiYuan Huang val->strval = rt9756_model[data->model]; 418*b6f0796dSChiYuan Huang return 0; 419*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_MANUFACTURER: 420*b6f0796dSChiYuan Huang val->strval = rt9756_manufacturer; 421*b6f0796dSChiYuan Huang return 0; 422*b6f0796dSChiYuan Huang default: 423*b6f0796dSChiYuan Huang return -ENODATA; 424*b6f0796dSChiYuan Huang } 425*b6f0796dSChiYuan Huang } 426*b6f0796dSChiYuan Huang 427*b6f0796dSChiYuan Huang static int rt9756_psy_set_property(struct power_supply *psy, 428*b6f0796dSChiYuan Huang enum power_supply_property psp, 429*b6f0796dSChiYuan Huang const union power_supply_propval *val) 430*b6f0796dSChiYuan Huang { 431*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 432*b6f0796dSChiYuan Huang int intval = val->intval; 433*b6f0796dSChiYuan Huang 434*b6f0796dSChiYuan Huang switch (psp) { 435*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_STATUS: 436*b6f0796dSChiYuan Huang memset(&data->chg_evt, 0, sizeof(data->chg_evt)); 437*b6f0796dSChiYuan Huang return regmap_field_write(data->rm_fields[F_CHG_EN], !!intval); 438*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_VOLTAGE_MAX: 439*b6f0796dSChiYuan Huang return rt9756_set_vbus_ovp(data, intval); 440*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CURRENT_MAX: 441*b6f0796dSChiYuan Huang return rt9756_set_value_field_range(data, F_IBUSOCP_EN, F_IBUSOCP, R_IBUSOCP, 442*b6f0796dSChiYuan Huang intval); 443*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 444*b6f0796dSChiYuan Huang return rt9756_set_value_field_range(data, F_VBATOVP_EN, F_VBATOVP, R_VBATOVP, 445*b6f0796dSChiYuan Huang intval); 446*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 447*b6f0796dSChiYuan Huang return rt9756_set_value_field_range(data, F_IBATOCP_EN, F_IBATOCP, R_IBATOCP, 448*b6f0796dSChiYuan Huang intval); 449*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_USB_TYPE: 450*b6f0796dSChiYuan Huang return regmap_field_write(data->rm_fields[F_BC12_EN], !!intval); 451*b6f0796dSChiYuan Huang default: 452*b6f0796dSChiYuan Huang return -EINVAL; 453*b6f0796dSChiYuan Huang } 454*b6f0796dSChiYuan Huang } 455*b6f0796dSChiYuan Huang 456*b6f0796dSChiYuan Huang static const enum power_supply_property rt9756_psy_properties[] = { 457*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_STATUS, 458*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_ONLINE, 459*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_HEALTH, 460*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_ONLINE, 461*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_VOLTAGE_MAX, 462*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_VOLTAGE_NOW, 463*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_CURRENT_MAX, 464*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_CURRENT_NOW, 465*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 466*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 467*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_TEMP, 468*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_USB_TYPE, 469*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_MODEL_NAME, 470*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_MANUFACTURER, 471*b6f0796dSChiYuan Huang }; 472*b6f0796dSChiYuan Huang 473*b6f0796dSChiYuan Huang static int rt9756_bat_psy_get_property(struct power_supply *psy, 474*b6f0796dSChiYuan Huang enum power_supply_property psp, 475*b6f0796dSChiYuan Huang union power_supply_propval *val) 476*b6f0796dSChiYuan Huang { 477*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 478*b6f0796dSChiYuan Huang int *pval = &val->intval; 479*b6f0796dSChiYuan Huang 480*b6f0796dSChiYuan Huang switch (psp) { 481*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_TECHNOLOGY: 482*b6f0796dSChiYuan Huang *pval = POWER_SUPPLY_TECHNOLOGY_LION; 483*b6f0796dSChiYuan Huang return 0; 484*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_VOLTAGE_NOW: 485*b6f0796dSChiYuan Huang return rt9756_get_adc(data, ADC_VBAT, pval); 486*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CURRENT_NOW: 487*b6f0796dSChiYuan Huang return rt9756_get_adc(data, ADC_IBAT, pval); 488*b6f0796dSChiYuan Huang default: 489*b6f0796dSChiYuan Huang return -ENODATA; 490*b6f0796dSChiYuan Huang } 491*b6f0796dSChiYuan Huang } 492*b6f0796dSChiYuan Huang 493*b6f0796dSChiYuan Huang static const enum power_supply_property rt9756_bat_psy_properties[] = { 494*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_TECHNOLOGY, 495*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_VOLTAGE_NOW, 496*b6f0796dSChiYuan Huang POWER_SUPPLY_PROP_CURRENT_NOW, 497*b6f0796dSChiYuan Huang }; 498*b6f0796dSChiYuan Huang 499*b6f0796dSChiYuan Huang static int rt9756_psy_property_is_writeable(struct power_supply *psy, 500*b6f0796dSChiYuan Huang enum power_supply_property psp) 501*b6f0796dSChiYuan Huang { 502*b6f0796dSChiYuan Huang switch (psp) { 503*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_STATUS: 504*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_ONLINE: 505*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_VOLTAGE_MAX: 506*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CURRENT_MAX: 507*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 508*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 509*b6f0796dSChiYuan Huang case POWER_SUPPLY_PROP_USB_TYPE: 510*b6f0796dSChiYuan Huang return 1; 511*b6f0796dSChiYuan Huang default: 512*b6f0796dSChiYuan Huang return 0; 513*b6f0796dSChiYuan Huang } 514*b6f0796dSChiYuan Huang } 515*b6f0796dSChiYuan Huang 516*b6f0796dSChiYuan Huang static const unsigned int rt9756_wdt_millisecond[] = { 517*b6f0796dSChiYuan Huang 500, 1000, 5000, 30000, 40000, 80000, 128000, 255000 518*b6f0796dSChiYuan Huang }; 519*b6f0796dSChiYuan Huang 520*b6f0796dSChiYuan Huang static ssize_t watchdog_timer_show(struct device *dev, 521*b6f0796dSChiYuan Huang struct device_attribute *attr, char *buf) 522*b6f0796dSChiYuan Huang { 523*b6f0796dSChiYuan Huang struct power_supply *psy = to_power_supply(dev); 524*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 525*b6f0796dSChiYuan Huang unsigned int wdt_tmr_now = 0, wdt_sel, wdt_dis; 526*b6f0796dSChiYuan Huang int ret; 527*b6f0796dSChiYuan Huang 528*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_WDT_DIS], &wdt_dis); 529*b6f0796dSChiYuan Huang if (ret) 530*b6f0796dSChiYuan Huang return ret; 531*b6f0796dSChiYuan Huang 532*b6f0796dSChiYuan Huang if (!wdt_dis) { 533*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_WDT_TMR], &wdt_sel); 534*b6f0796dSChiYuan Huang if (ret) 535*b6f0796dSChiYuan Huang return ret; 536*b6f0796dSChiYuan Huang 537*b6f0796dSChiYuan Huang wdt_tmr_now = rt9756_wdt_millisecond[wdt_sel]; 538*b6f0796dSChiYuan Huang } 539*b6f0796dSChiYuan Huang 540*b6f0796dSChiYuan Huang return sysfs_emit(buf, "%d\n", wdt_tmr_now); 541*b6f0796dSChiYuan Huang } 542*b6f0796dSChiYuan Huang 543*b6f0796dSChiYuan Huang static ssize_t watchdog_timer_store(struct device *dev, 544*b6f0796dSChiYuan Huang struct device_attribute *attr, 545*b6f0796dSChiYuan Huang const char *buf, size_t count) 546*b6f0796dSChiYuan Huang { 547*b6f0796dSChiYuan Huang struct power_supply *psy = to_power_supply(dev); 548*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 549*b6f0796dSChiYuan Huang unsigned int wdt_set, wdt_sel; 550*b6f0796dSChiYuan Huang int ret; 551*b6f0796dSChiYuan Huang 552*b6f0796dSChiYuan Huang ret = kstrtouint(buf, 10, &wdt_set); 553*b6f0796dSChiYuan Huang if (ret) 554*b6f0796dSChiYuan Huang return ret; 555*b6f0796dSChiYuan Huang 556*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[F_WDT_DIS], 1); 557*b6f0796dSChiYuan Huang if (ret) 558*b6f0796dSChiYuan Huang return ret; 559*b6f0796dSChiYuan Huang 560*b6f0796dSChiYuan Huang wdt_sel = find_closest(wdt_set, rt9756_wdt_millisecond, 561*b6f0796dSChiYuan Huang ARRAY_SIZE(rt9756_wdt_millisecond)); 562*b6f0796dSChiYuan Huang 563*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[F_WDT_TMR], wdt_sel); 564*b6f0796dSChiYuan Huang if (ret) 565*b6f0796dSChiYuan Huang return ret; 566*b6f0796dSChiYuan Huang 567*b6f0796dSChiYuan Huang if (wdt_set) { 568*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[F_WDT_DIS], 0); 569*b6f0796dSChiYuan Huang if (ret) 570*b6f0796dSChiYuan Huang return ret; 571*b6f0796dSChiYuan Huang } 572*b6f0796dSChiYuan Huang 573*b6f0796dSChiYuan Huang return count; 574*b6f0796dSChiYuan Huang } 575*b6f0796dSChiYuan Huang 576*b6f0796dSChiYuan Huang static const char * const rt9756_opmode_str[] = { "bypass", "div2" }; 577*b6f0796dSChiYuan Huang 578*b6f0796dSChiYuan Huang static ssize_t operation_mode_show(struct device *dev, 579*b6f0796dSChiYuan Huang struct device_attribute *attr, char *buf) 580*b6f0796dSChiYuan Huang { 581*b6f0796dSChiYuan Huang struct power_supply *psy = to_power_supply(dev); 582*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 583*b6f0796dSChiYuan Huang unsigned int opmode; 584*b6f0796dSChiYuan Huang int ret; 585*b6f0796dSChiYuan Huang 586*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_OP_MODE], &opmode); 587*b6f0796dSChiYuan Huang if (ret) 588*b6f0796dSChiYuan Huang return ret; 589*b6f0796dSChiYuan Huang 590*b6f0796dSChiYuan Huang return sysfs_emit(buf, "%s\n", rt9756_opmode_str[opmode]); 591*b6f0796dSChiYuan Huang } 592*b6f0796dSChiYuan Huang 593*b6f0796dSChiYuan Huang static ssize_t operation_mode_store(struct device *dev, 594*b6f0796dSChiYuan Huang struct device_attribute *attr, 595*b6f0796dSChiYuan Huang const char *buf, size_t count) 596*b6f0796dSChiYuan Huang { 597*b6f0796dSChiYuan Huang struct power_supply *psy = to_power_supply(dev); 598*b6f0796dSChiYuan Huang struct rt9756_data *data = power_supply_get_drvdata(psy); 599*b6f0796dSChiYuan Huang int index, ret; 600*b6f0796dSChiYuan Huang 601*b6f0796dSChiYuan Huang index = sysfs_match_string(rt9756_opmode_str, buf); 602*b6f0796dSChiYuan Huang if (index < 0) 603*b6f0796dSChiYuan Huang return index; 604*b6f0796dSChiYuan Huang 605*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[F_OP_MODE], index); 606*b6f0796dSChiYuan Huang 607*b6f0796dSChiYuan Huang return ret ?: count; 608*b6f0796dSChiYuan Huang } 609*b6f0796dSChiYuan Huang 610*b6f0796dSChiYuan Huang static DEVICE_ATTR_RW(watchdog_timer); 611*b6f0796dSChiYuan Huang static DEVICE_ATTR_RW(operation_mode); 612*b6f0796dSChiYuan Huang 613*b6f0796dSChiYuan Huang static struct attribute *rt9756_sysfs_attrs[] = { 614*b6f0796dSChiYuan Huang &dev_attr_watchdog_timer.attr, 615*b6f0796dSChiYuan Huang &dev_attr_operation_mode.attr, 616*b6f0796dSChiYuan Huang NULL 617*b6f0796dSChiYuan Huang }; 618*b6f0796dSChiYuan Huang ATTRIBUTE_GROUPS(rt9756_sysfs); 619*b6f0796dSChiYuan Huang 620*b6f0796dSChiYuan Huang static int rt9756_register_psy(struct rt9756_data *data) 621*b6f0796dSChiYuan Huang { 622*b6f0796dSChiYuan Huang struct power_supply_desc *desc = &data->psy_desc; 623*b6f0796dSChiYuan Huang struct power_supply_desc *bat_desc = &data->bat_psy_desc; 624*b6f0796dSChiYuan Huang struct power_supply_config cfg = {}, bat_cfg = {}; 625*b6f0796dSChiYuan Huang struct device *dev = data->dev; 626*b6f0796dSChiYuan Huang char *psy_name, *bat_psy_name, **supplied_to; 627*b6f0796dSChiYuan Huang 628*b6f0796dSChiYuan Huang bat_cfg.drv_data = data; 629*b6f0796dSChiYuan Huang bat_cfg.fwnode = dev_fwnode(dev); 630*b6f0796dSChiYuan Huang 631*b6f0796dSChiYuan Huang bat_psy_name = devm_kasprintf(dev, GFP_KERNEL, "rt9756-%s-battery", dev_name(dev)); 632*b6f0796dSChiYuan Huang if (!bat_psy_name) 633*b6f0796dSChiYuan Huang return -ENOMEM; 634*b6f0796dSChiYuan Huang 635*b6f0796dSChiYuan Huang bat_desc->name = bat_psy_name; 636*b6f0796dSChiYuan Huang bat_desc->type = POWER_SUPPLY_TYPE_BATTERY; 637*b6f0796dSChiYuan Huang bat_desc->properties = rt9756_bat_psy_properties; 638*b6f0796dSChiYuan Huang bat_desc->num_properties = ARRAY_SIZE(rt9756_bat_psy_properties); 639*b6f0796dSChiYuan Huang bat_desc->get_property = rt9756_bat_psy_get_property; 640*b6f0796dSChiYuan Huang 641*b6f0796dSChiYuan Huang data->bat_psy = devm_power_supply_register(dev, bat_desc, &bat_cfg); 642*b6f0796dSChiYuan Huang if (IS_ERR(data->bat_psy)) 643*b6f0796dSChiYuan Huang return dev_err_probe(dev, PTR_ERR(data->bat_psy), "Failed to register battery\n"); 644*b6f0796dSChiYuan Huang 645*b6f0796dSChiYuan Huang supplied_to = devm_kzalloc(dev, sizeof(*supplied_to), GFP_KERNEL); 646*b6f0796dSChiYuan Huang if (!supplied_to) 647*b6f0796dSChiYuan Huang return -ENOMEM; 648*b6f0796dSChiYuan Huang 649*b6f0796dSChiYuan Huang /* Link charger psy to battery psy */ 650*b6f0796dSChiYuan Huang supplied_to[0] = bat_psy_name; 651*b6f0796dSChiYuan Huang 652*b6f0796dSChiYuan Huang cfg.drv_data = data; 653*b6f0796dSChiYuan Huang cfg.fwnode = dev_fwnode(dev); 654*b6f0796dSChiYuan Huang cfg.attr_grp = rt9756_sysfs_groups; 655*b6f0796dSChiYuan Huang cfg.supplied_to = supplied_to; 656*b6f0796dSChiYuan Huang cfg.num_supplicants = 1; 657*b6f0796dSChiYuan Huang 658*b6f0796dSChiYuan Huang psy_name = devm_kasprintf(dev, GFP_KERNEL, "rt9756-%s", dev_name(dev)); 659*b6f0796dSChiYuan Huang if (!psy_name) 660*b6f0796dSChiYuan Huang return -ENOMEM; 661*b6f0796dSChiYuan Huang 662*b6f0796dSChiYuan Huang desc->name = psy_name; 663*b6f0796dSChiYuan Huang desc->type = POWER_SUPPLY_TYPE_USB; 664*b6f0796dSChiYuan Huang desc->usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) | BIT(POWER_SUPPLY_USB_TYPE_SDP) | 665*b6f0796dSChiYuan Huang BIT(POWER_SUPPLY_USB_TYPE_DCP) | BIT(POWER_SUPPLY_USB_TYPE_CDP); 666*b6f0796dSChiYuan Huang desc->properties = rt9756_psy_properties; 667*b6f0796dSChiYuan Huang desc->num_properties = ARRAY_SIZE(rt9756_psy_properties); 668*b6f0796dSChiYuan Huang desc->property_is_writeable = rt9756_psy_property_is_writeable; 669*b6f0796dSChiYuan Huang desc->get_property = rt9756_psy_get_property; 670*b6f0796dSChiYuan Huang desc->set_property = rt9756_psy_set_property; 671*b6f0796dSChiYuan Huang 672*b6f0796dSChiYuan Huang data->psy = devm_power_supply_register(dev, desc, &cfg); 673*b6f0796dSChiYuan Huang 674*b6f0796dSChiYuan Huang return PTR_ERR_OR_ZERO(data->psy); 675*b6f0796dSChiYuan Huang } 676*b6f0796dSChiYuan Huang 677*b6f0796dSChiYuan Huang static int rt9756_get_usb_type(struct rt9756_data *data) 678*b6f0796dSChiYuan Huang { 679*b6f0796dSChiYuan Huang unsigned int type; 680*b6f0796dSChiYuan Huang int report_type, ret; 681*b6f0796dSChiYuan Huang 682*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_USB_STATE], &type); 683*b6f0796dSChiYuan Huang if (ret) 684*b6f0796dSChiYuan Huang return ret; 685*b6f0796dSChiYuan Huang 686*b6f0796dSChiYuan Huang switch (type) { 687*b6f0796dSChiYuan Huang case USB_SDP: 688*b6f0796dSChiYuan Huang case USB_NSTD: 689*b6f0796dSChiYuan Huang report_type = POWER_SUPPLY_USB_TYPE_SDP; 690*b6f0796dSChiYuan Huang break; 691*b6f0796dSChiYuan Huang case USB_DCP: 692*b6f0796dSChiYuan Huang report_type = POWER_SUPPLY_USB_TYPE_DCP; 693*b6f0796dSChiYuan Huang break; 694*b6f0796dSChiYuan Huang case USB_CDP: 695*b6f0796dSChiYuan Huang report_type = POWER_SUPPLY_USB_TYPE_CDP; 696*b6f0796dSChiYuan Huang break; 697*b6f0796dSChiYuan Huang case USB_NO_VBUS: 698*b6f0796dSChiYuan Huang default: 699*b6f0796dSChiYuan Huang report_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; 700*b6f0796dSChiYuan Huang break; 701*b6f0796dSChiYuan Huang } 702*b6f0796dSChiYuan Huang 703*b6f0796dSChiYuan Huang atomic_set(&data->usb_type, report_type); 704*b6f0796dSChiYuan Huang return 0; 705*b6f0796dSChiYuan Huang } 706*b6f0796dSChiYuan Huang 707*b6f0796dSChiYuan Huang static irqreturn_t rt9756_irq_handler(int irq, void *devid) 708*b6f0796dSChiYuan Huang { 709*b6f0796dSChiYuan Huang struct rt9756_data *data = devid; 710*b6f0796dSChiYuan Huang struct regmap *regmap = data->regmap; 711*b6f0796dSChiYuan Huang struct charger_event *evt = &data->chg_evt; 712*b6f0796dSChiYuan Huang unsigned int bc12_flag = 0; 713*b6f0796dSChiYuan Huang int ret; 714*b6f0796dSChiYuan Huang 715*b6f0796dSChiYuan Huang ret = regmap_read(regmap, RT9756_REG_INTFLAG1, &evt->flag1); 716*b6f0796dSChiYuan Huang if (ret) 717*b6f0796dSChiYuan Huang return IRQ_NONE; 718*b6f0796dSChiYuan Huang 719*b6f0796dSChiYuan Huang ret = regmap_read(regmap, RT9756_REG_INTFLAG2, &evt->flag2); 720*b6f0796dSChiYuan Huang if (ret) 721*b6f0796dSChiYuan Huang return IRQ_NONE; 722*b6f0796dSChiYuan Huang 723*b6f0796dSChiYuan Huang ret = regmap_read(regmap, RT9756_REG_INTFLAG3, &evt->flag3); 724*b6f0796dSChiYuan Huang if (ret) 725*b6f0796dSChiYuan Huang return IRQ_NONE; 726*b6f0796dSChiYuan Huang 727*b6f0796dSChiYuan Huang if (data->model != MODEL_RT9770) { 728*b6f0796dSChiYuan Huang ret = regmap_read(regmap, RT9756_REG_INTFLAG4, &evt->flag4); 729*b6f0796dSChiYuan Huang if (ret) 730*b6f0796dSChiYuan Huang return IRQ_NONE; 731*b6f0796dSChiYuan Huang 732*b6f0796dSChiYuan Huang ret = regmap_read(regmap, RT9756_REG_BC12FLAG, &bc12_flag); 733*b6f0796dSChiYuan Huang if (ret) 734*b6f0796dSChiYuan Huang return IRQ_NONE; 735*b6f0796dSChiYuan Huang } 736*b6f0796dSChiYuan Huang 737*b6f0796dSChiYuan Huang dev_dbg(data->dev, "events: 0x%02x,%02x,%02x,%02x,%02x\n", evt->flag1, evt->flag2, 738*b6f0796dSChiYuan Huang evt->flag3, evt->flag4, bc12_flag); 739*b6f0796dSChiYuan Huang 740*b6f0796dSChiYuan Huang if (evt->flag2 & RT9756_EVT_VAC_INSERT) { 741*b6f0796dSChiYuan Huang ret = regmap_field_write(data->rm_fields[F_BC12_EN], 1); 742*b6f0796dSChiYuan Huang if (ret) 743*b6f0796dSChiYuan Huang return IRQ_NONE; 744*b6f0796dSChiYuan Huang } 745*b6f0796dSChiYuan Huang 746*b6f0796dSChiYuan Huang if (evt->flag3 & RT9756_EVT_VAC_UVLO) 747*b6f0796dSChiYuan Huang atomic_set(&data->usb_type, POWER_SUPPLY_USB_TYPE_UNKNOWN); 748*b6f0796dSChiYuan Huang 749*b6f0796dSChiYuan Huang if (bc12_flag & RT9756_EVT_BC12_DONE) { 750*b6f0796dSChiYuan Huang ret = rt9756_get_usb_type(data); 751*b6f0796dSChiYuan Huang if (ret) 752*b6f0796dSChiYuan Huang return IRQ_NONE; 753*b6f0796dSChiYuan Huang } 754*b6f0796dSChiYuan Huang 755*b6f0796dSChiYuan Huang power_supply_changed(data->psy); 756*b6f0796dSChiYuan Huang 757*b6f0796dSChiYuan Huang return IRQ_HANDLED; 758*b6f0796dSChiYuan Huang } 759*b6f0796dSChiYuan Huang 760*b6f0796dSChiYuan Huang static int rt9756_config_batsense_resistor(struct rt9756_data *data) 761*b6f0796dSChiYuan Huang { 762*b6f0796dSChiYuan Huang unsigned int shunt_resistor_uohms = 2000, rsense_sel; 763*b6f0796dSChiYuan Huang 764*b6f0796dSChiYuan Huang device_property_read_u32(data->dev, "shunt-resistor-micro-ohms", &shunt_resistor_uohms); 765*b6f0796dSChiYuan Huang 766*b6f0796dSChiYuan Huang if (!shunt_resistor_uohms || shunt_resistor_uohms > 5000) 767*b6f0796dSChiYuan Huang return -EINVAL; 768*b6f0796dSChiYuan Huang 769*b6f0796dSChiYuan Huang data->real_resistor = shunt_resistor_uohms; 770*b6f0796dSChiYuan Huang 771*b6f0796dSChiYuan Huang /* Always choose the larger or equal one to prevent false ocp alarm */ 772*b6f0796dSChiYuan Huang if (shunt_resistor_uohms <= 1000) { 773*b6f0796dSChiYuan Huang rsense_sel = 0; 774*b6f0796dSChiYuan Huang data->rg_resistor = 1000; 775*b6f0796dSChiYuan Huang } else if (shunt_resistor_uohms <= 2000) { 776*b6f0796dSChiYuan Huang rsense_sel = 1; 777*b6f0796dSChiYuan Huang data->rg_resistor = 2000; 778*b6f0796dSChiYuan Huang } else { 779*b6f0796dSChiYuan Huang rsense_sel = 2; 780*b6f0796dSChiYuan Huang data->rg_resistor = 5000; 781*b6f0796dSChiYuan Huang } 782*b6f0796dSChiYuan Huang 783*b6f0796dSChiYuan Huang return regmap_field_write(data->rm_fields[F_IBAT_RSEN], rsense_sel); 784*b6f0796dSChiYuan Huang } 785*b6f0796dSChiYuan Huang 786*b6f0796dSChiYuan Huang static const struct reg_sequence rt9756_init_regs[] = { 787*b6f0796dSChiYuan Huang REG_SEQ(0x00, 0x80, 1000), /* REG_RESET */ 788*b6f0796dSChiYuan Huang REG_SEQ0(0x04, 0x13), /* VACOVP/OVPGATE 12V */ 789*b6f0796dSChiYuan Huang REG_SEQ0(0x00, 0x28), /* WDT_DIS = 1 */ 790*b6f0796dSChiYuan Huang REG_SEQ0(0x0c, 0x02), /* MASK FLAG1 */ 791*b6f0796dSChiYuan Huang REG_SEQ0(0x0e, 0x06), /* MASK FLAG2 */ 792*b6f0796dSChiYuan Huang REG_SEQ0(0x10, 0xca), /* MASK FLAG3 */ 793*b6f0796dSChiYuan Huang REG_SEQ0(0x44, 0xa0), /* BC12_EN */ 794*b6f0796dSChiYuan Huang REG_SEQ0(0x47, 0x07), /* MASK BC12FLAG */ 795*b6f0796dSChiYuan Huang REG_SEQ0(0x4a, 0xfe), /* MASK FLAG4 */ 796*b6f0796dSChiYuan Huang REG_SEQ0(0x5c, 0x40), /* MASK CON_SWITCHING */ 797*b6f0796dSChiYuan Huang REG_SEQ0(0x63, 0x01), /* MASK VDDA_UVLO */ 798*b6f0796dSChiYuan Huang }; 799*b6f0796dSChiYuan Huang 800*b6f0796dSChiYuan Huang static const struct reg_sequence rt9770_init_regs[] = { 801*b6f0796dSChiYuan Huang REG_SEQ(0x00, 0x80, 1000), /* REG_RESET */ 802*b6f0796dSChiYuan Huang REG_SEQ0(0x04, 0x13), /* VACOVP/OVPGATE 12V */ 803*b6f0796dSChiYuan Huang REG_SEQ0(0x00, 0x28), /* WDT_DIS = 1 */ 804*b6f0796dSChiYuan Huang REG_SEQ0(0x0c, 0x02), /* MASK FLAG1 */ 805*b6f0796dSChiYuan Huang REG_SEQ0(0x0e, 0x06), /* MASK FLAG2 */ 806*b6f0796dSChiYuan Huang REG_SEQ0(0x10, 0xca), /* MASK FLAG3 */ 807*b6f0796dSChiYuan Huang REG_SEQ0(0x5c, 0x40), /* MASK CON_SWITCHING */ 808*b6f0796dSChiYuan Huang REG_SEQ0(0x63, 0x01), /* MASK VDDA_UVLO */ 809*b6f0796dSChiYuan Huang }; 810*b6f0796dSChiYuan Huang 811*b6f0796dSChiYuan Huang static const struct regmap_config rt9756_regmap_config = { 812*b6f0796dSChiYuan Huang .name = "rt9756", 813*b6f0796dSChiYuan Huang .reg_bits = 16, 814*b6f0796dSChiYuan Huang .val_bits = 8, 815*b6f0796dSChiYuan Huang .max_register = 0x1ff, 816*b6f0796dSChiYuan Huang }; 817*b6f0796dSChiYuan Huang 818*b6f0796dSChiYuan Huang static const struct regmap_config rt9770_regmap_config = { 819*b6f0796dSChiYuan Huang .name = "rt9770", 820*b6f0796dSChiYuan Huang .reg_bits = 8, 821*b6f0796dSChiYuan Huang .val_bits = 8, 822*b6f0796dSChiYuan Huang .max_register = 0xff, 823*b6f0796dSChiYuan Huang }; 824*b6f0796dSChiYuan Huang 825*b6f0796dSChiYuan Huang static int rt9756_check_device_model(struct rt9756_data *data) 826*b6f0796dSChiYuan Huang { 827*b6f0796dSChiYuan Huang struct device *dev = data->dev; 828*b6f0796dSChiYuan Huang unsigned int revid; 829*b6f0796dSChiYuan Huang int ret; 830*b6f0796dSChiYuan Huang 831*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_REVISION], &revid); 832*b6f0796dSChiYuan Huang if (ret) 833*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to read revid\n"); 834*b6f0796dSChiYuan Huang 835*b6f0796dSChiYuan Huang if (revid == RT9757_REVID || revid == RT9757A_REVID) 836*b6f0796dSChiYuan Huang data->model = MODEL_RT9757; 837*b6f0796dSChiYuan Huang else if (revid == RT9756_REVID || revid == RT9756A_REVID) 838*b6f0796dSChiYuan Huang data->model = MODEL_RT9756; 839*b6f0796dSChiYuan Huang else 840*b6f0796dSChiYuan Huang return dev_err_probe(dev, -EINVAL, "Unknown revision %d\n", revid); 841*b6f0796dSChiYuan Huang 842*b6f0796dSChiYuan Huang return 0; 843*b6f0796dSChiYuan Huang } 844*b6f0796dSChiYuan Huang 845*b6f0796dSChiYuan Huang static int rt9770_check_device_model(struct rt9756_data *data) 846*b6f0796dSChiYuan Huang { 847*b6f0796dSChiYuan Huang data->model = MODEL_RT9770; 848*b6f0796dSChiYuan Huang return 0; 849*b6f0796dSChiYuan Huang } 850*b6f0796dSChiYuan Huang 851*b6f0796dSChiYuan Huang static int rt9756_probe(struct i2c_client *i2c) 852*b6f0796dSChiYuan Huang { 853*b6f0796dSChiYuan Huang const struct rt975x_dev_data *dev_data; 854*b6f0796dSChiYuan Huang struct device *dev = &i2c->dev; 855*b6f0796dSChiYuan Huang struct rt9756_data *data; 856*b6f0796dSChiYuan Huang struct regmap *regmap; 857*b6f0796dSChiYuan Huang unsigned int devid; 858*b6f0796dSChiYuan Huang int ret; 859*b6f0796dSChiYuan Huang 860*b6f0796dSChiYuan Huang dev_data = device_get_match_data(dev); 861*b6f0796dSChiYuan Huang if (!dev_data) 862*b6f0796dSChiYuan Huang return dev_err_probe(dev, -EINVAL, "No device data found\n"); 863*b6f0796dSChiYuan Huang 864*b6f0796dSChiYuan Huang data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 865*b6f0796dSChiYuan Huang if (!data) 866*b6f0796dSChiYuan Huang return -ENOMEM; 867*b6f0796dSChiYuan Huang 868*b6f0796dSChiYuan Huang data->dev = dev; 869*b6f0796dSChiYuan Huang mutex_init(&data->adc_lock); 870*b6f0796dSChiYuan Huang atomic_set(&data->usb_type, POWER_SUPPLY_USB_TYPE_UNKNOWN); 871*b6f0796dSChiYuan Huang i2c_set_clientdata(i2c, data); 872*b6f0796dSChiYuan Huang 873*b6f0796dSChiYuan Huang regmap = devm_regmap_init_i2c(i2c, dev_data->regmap_config); 874*b6f0796dSChiYuan Huang if (IS_ERR(regmap)) 875*b6f0796dSChiYuan Huang return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n"); 876*b6f0796dSChiYuan Huang 877*b6f0796dSChiYuan Huang data->regmap = regmap; 878*b6f0796dSChiYuan Huang 879*b6f0796dSChiYuan Huang ret = devm_regmap_field_bulk_alloc(dev, regmap, data->rm_fields, dev_data->reg_fields, 880*b6f0796dSChiYuan Huang F_MAX_FIELD); 881*b6f0796dSChiYuan Huang if (ret) 882*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to alloc regmap fields\n"); 883*b6f0796dSChiYuan Huang 884*b6f0796dSChiYuan Huang /* Richtek Device ID check */ 885*b6f0796dSChiYuan Huang ret = regmap_field_read(data->rm_fields[F_DEV_ID], &devid); 886*b6f0796dSChiYuan Huang if (ret) 887*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to read devid\n"); 888*b6f0796dSChiYuan Huang 889*b6f0796dSChiYuan Huang if (devid != RICHTEK_DEVID) 890*b6f0796dSChiYuan Huang return dev_err_probe(dev, -ENODEV, "Incorrect VID 0x%02x\n", devid); 891*b6f0796dSChiYuan Huang 892*b6f0796dSChiYuan Huang /* Get specific model */ 893*b6f0796dSChiYuan Huang ret = dev_data->check_device_model(data); 894*b6f0796dSChiYuan Huang if (ret) 895*b6f0796dSChiYuan Huang return ret; 896*b6f0796dSChiYuan Huang 897*b6f0796dSChiYuan Huang ret = regmap_register_patch(regmap, dev_data->init_regs, dev_data->num_init_regs); 898*b6f0796dSChiYuan Huang if (ret) 899*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to init registers\n"); 900*b6f0796dSChiYuan Huang 901*b6f0796dSChiYuan Huang ret = rt9756_config_batsense_resistor(data); 902*b6f0796dSChiYuan Huang if (ret) 903*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to config batsense resistor\n"); 904*b6f0796dSChiYuan Huang 905*b6f0796dSChiYuan Huang ret = rt9756_register_psy(data); 906*b6f0796dSChiYuan Huang if (ret) 907*b6f0796dSChiYuan Huang return dev_err_probe(dev, ret, "Failed to init power supply\n"); 908*b6f0796dSChiYuan Huang 909*b6f0796dSChiYuan Huang return devm_request_threaded_irq(dev, i2c->irq, NULL, rt9756_irq_handler, IRQF_ONESHOT, 910*b6f0796dSChiYuan Huang dev_name(dev), data); 911*b6f0796dSChiYuan Huang } 912*b6f0796dSChiYuan Huang 913*b6f0796dSChiYuan Huang static void rt9756_shutdown(struct i2c_client *i2c) 914*b6f0796dSChiYuan Huang { 915*b6f0796dSChiYuan Huang struct rt9756_data *data = i2c_get_clientdata(i2c); 916*b6f0796dSChiYuan Huang 917*b6f0796dSChiYuan Huang regmap_field_write(data->rm_fields[F_REG_RST], 1); 918*b6f0796dSChiYuan Huang } 919*b6f0796dSChiYuan Huang 920*b6f0796dSChiYuan Huang static const struct rt975x_dev_data rt9756_dev_data = { 921*b6f0796dSChiYuan Huang .regmap_config = &rt9756_regmap_config, 922*b6f0796dSChiYuan Huang .reg_fields = rt9756_chg_fields, 923*b6f0796dSChiYuan Huang .init_regs = rt9756_init_regs, 924*b6f0796dSChiYuan Huang .num_init_regs = ARRAY_SIZE(rt9756_init_regs), 925*b6f0796dSChiYuan Huang .check_device_model = rt9756_check_device_model, 926*b6f0796dSChiYuan Huang }; 927*b6f0796dSChiYuan Huang 928*b6f0796dSChiYuan Huang static const struct rt975x_dev_data rt9770_dev_data = { 929*b6f0796dSChiYuan Huang .regmap_config = &rt9770_regmap_config, 930*b6f0796dSChiYuan Huang .reg_fields = rt9770_chg_fields, 931*b6f0796dSChiYuan Huang .init_regs = rt9770_init_regs, 932*b6f0796dSChiYuan Huang .num_init_regs = ARRAY_SIZE(rt9770_init_regs), 933*b6f0796dSChiYuan Huang .check_device_model = rt9770_check_device_model, 934*b6f0796dSChiYuan Huang }; 935*b6f0796dSChiYuan Huang 936*b6f0796dSChiYuan Huang static const struct of_device_id rt9756_device_match_table[] = { 937*b6f0796dSChiYuan Huang { .compatible = "richtek,rt9756", .data = &rt9756_dev_data }, 938*b6f0796dSChiYuan Huang { .compatible = "richtek,rt9770", .data = &rt9770_dev_data }, 939*b6f0796dSChiYuan Huang {} 940*b6f0796dSChiYuan Huang }; 941*b6f0796dSChiYuan Huang MODULE_DEVICE_TABLE(of, rt9756_device_match_table); 942*b6f0796dSChiYuan Huang 943*b6f0796dSChiYuan Huang static struct i2c_driver rt9756_charger_driver = { 944*b6f0796dSChiYuan Huang .driver = { 945*b6f0796dSChiYuan Huang .name = "rt9756", 946*b6f0796dSChiYuan Huang .of_match_table = rt9756_device_match_table, 947*b6f0796dSChiYuan Huang }, 948*b6f0796dSChiYuan Huang .probe = rt9756_probe, 949*b6f0796dSChiYuan Huang .shutdown = rt9756_shutdown, 950*b6f0796dSChiYuan Huang }; 951*b6f0796dSChiYuan Huang module_i2c_driver(rt9756_charger_driver); 952*b6f0796dSChiYuan Huang 953*b6f0796dSChiYuan Huang MODULE_DESCRIPTION("Richtek RT9756 charger driver"); 954*b6f0796dSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 955*b6f0796dSChiYuan Huang MODULE_LICENSE("GPL"); 956