1*8c0984e5SSebastian Reichel /* 2*8c0984e5SSebastian Reichel * max77693_charger.c - Battery charger driver for the Maxim 77693 3*8c0984e5SSebastian Reichel * 4*8c0984e5SSebastian Reichel * Copyright (C) 2014 Samsung Electronics 5*8c0984e5SSebastian Reichel * Krzysztof Kozlowski <k.kozlowski@samsung.com> 6*8c0984e5SSebastian Reichel * 7*8c0984e5SSebastian Reichel * This program is free software; you can redistribute it and/or modify 8*8c0984e5SSebastian Reichel * it under the terms of the GNU General Public License as published by 9*8c0984e5SSebastian Reichel * the Free Software Foundation; either version 2 of the License, or 10*8c0984e5SSebastian Reichel * (at your option) any later version. 11*8c0984e5SSebastian Reichel * 12*8c0984e5SSebastian Reichel * This program is distributed in the hope that it will be useful, 13*8c0984e5SSebastian Reichel * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*8c0984e5SSebastian Reichel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*8c0984e5SSebastian Reichel * GNU General Public License for more details. 16*8c0984e5SSebastian Reichel */ 17*8c0984e5SSebastian Reichel 18*8c0984e5SSebastian Reichel #include <linux/module.h> 19*8c0984e5SSebastian Reichel #include <linux/platform_device.h> 20*8c0984e5SSebastian Reichel #include <linux/power_supply.h> 21*8c0984e5SSebastian Reichel #include <linux/regmap.h> 22*8c0984e5SSebastian Reichel #include <linux/mfd/max77693.h> 23*8c0984e5SSebastian Reichel #include <linux/mfd/max77693-common.h> 24*8c0984e5SSebastian Reichel #include <linux/mfd/max77693-private.h> 25*8c0984e5SSebastian Reichel 26*8c0984e5SSebastian Reichel #define MAX77693_CHARGER_NAME "max77693-charger" 27*8c0984e5SSebastian Reichel static const char *max77693_charger_model = "MAX77693"; 28*8c0984e5SSebastian Reichel static const char *max77693_charger_manufacturer = "Maxim Integrated"; 29*8c0984e5SSebastian Reichel 30*8c0984e5SSebastian Reichel struct max77693_charger { 31*8c0984e5SSebastian Reichel struct device *dev; 32*8c0984e5SSebastian Reichel struct max77693_dev *max77693; 33*8c0984e5SSebastian Reichel struct power_supply *charger; 34*8c0984e5SSebastian Reichel 35*8c0984e5SSebastian Reichel u32 constant_volt; 36*8c0984e5SSebastian Reichel u32 min_system_volt; 37*8c0984e5SSebastian Reichel u32 thermal_regulation_temp; 38*8c0984e5SSebastian Reichel u32 batttery_overcurrent; 39*8c0984e5SSebastian Reichel u32 charge_input_threshold_volt; 40*8c0984e5SSebastian Reichel }; 41*8c0984e5SSebastian Reichel 42*8c0984e5SSebastian Reichel static int max77693_get_charger_state(struct regmap *regmap, int *val) 43*8c0984e5SSebastian Reichel { 44*8c0984e5SSebastian Reichel int ret; 45*8c0984e5SSebastian Reichel unsigned int data; 46*8c0984e5SSebastian Reichel 47*8c0984e5SSebastian Reichel ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data); 48*8c0984e5SSebastian Reichel if (ret < 0) 49*8c0984e5SSebastian Reichel return ret; 50*8c0984e5SSebastian Reichel 51*8c0984e5SSebastian Reichel data &= CHG_DETAILS_01_CHG_MASK; 52*8c0984e5SSebastian Reichel data >>= CHG_DETAILS_01_CHG_SHIFT; 53*8c0984e5SSebastian Reichel 54*8c0984e5SSebastian Reichel switch (data) { 55*8c0984e5SSebastian Reichel case MAX77693_CHARGING_PREQUALIFICATION: 56*8c0984e5SSebastian Reichel case MAX77693_CHARGING_FAST_CONST_CURRENT: 57*8c0984e5SSebastian Reichel case MAX77693_CHARGING_FAST_CONST_VOLTAGE: 58*8c0984e5SSebastian Reichel case MAX77693_CHARGING_TOP_OFF: 59*8c0984e5SSebastian Reichel /* In high temp the charging current is reduced, but still charging */ 60*8c0984e5SSebastian Reichel case MAX77693_CHARGING_HIGH_TEMP: 61*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_STATUS_CHARGING; 62*8c0984e5SSebastian Reichel break; 63*8c0984e5SSebastian Reichel case MAX77693_CHARGING_DONE: 64*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_STATUS_FULL; 65*8c0984e5SSebastian Reichel break; 66*8c0984e5SSebastian Reichel case MAX77693_CHARGING_TIMER_EXPIRED: 67*8c0984e5SSebastian Reichel case MAX77693_CHARGING_THERMISTOR_SUSPEND: 68*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 69*8c0984e5SSebastian Reichel break; 70*8c0984e5SSebastian Reichel case MAX77693_CHARGING_OFF: 71*8c0984e5SSebastian Reichel case MAX77693_CHARGING_OVER_TEMP: 72*8c0984e5SSebastian Reichel case MAX77693_CHARGING_WATCHDOG_EXPIRED: 73*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_STATUS_DISCHARGING; 74*8c0984e5SSebastian Reichel break; 75*8c0984e5SSebastian Reichel case MAX77693_CHARGING_RESERVED: 76*8c0984e5SSebastian Reichel default: 77*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_STATUS_UNKNOWN; 78*8c0984e5SSebastian Reichel } 79*8c0984e5SSebastian Reichel 80*8c0984e5SSebastian Reichel return 0; 81*8c0984e5SSebastian Reichel } 82*8c0984e5SSebastian Reichel 83*8c0984e5SSebastian Reichel static int max77693_get_charge_type(struct regmap *regmap, int *val) 84*8c0984e5SSebastian Reichel { 85*8c0984e5SSebastian Reichel int ret; 86*8c0984e5SSebastian Reichel unsigned int data; 87*8c0984e5SSebastian Reichel 88*8c0984e5SSebastian Reichel ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data); 89*8c0984e5SSebastian Reichel if (ret < 0) 90*8c0984e5SSebastian Reichel return ret; 91*8c0984e5SSebastian Reichel 92*8c0984e5SSebastian Reichel data &= CHG_DETAILS_01_CHG_MASK; 93*8c0984e5SSebastian Reichel data >>= CHG_DETAILS_01_CHG_SHIFT; 94*8c0984e5SSebastian Reichel 95*8c0984e5SSebastian Reichel switch (data) { 96*8c0984e5SSebastian Reichel case MAX77693_CHARGING_PREQUALIFICATION: 97*8c0984e5SSebastian Reichel /* 98*8c0984e5SSebastian Reichel * Top-off: trickle or fast? In top-off the current varies between 99*8c0984e5SSebastian Reichel * 100 and 250 mA. It is higher than prequalification current. 100*8c0984e5SSebastian Reichel */ 101*8c0984e5SSebastian Reichel case MAX77693_CHARGING_TOP_OFF: 102*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 103*8c0984e5SSebastian Reichel break; 104*8c0984e5SSebastian Reichel case MAX77693_CHARGING_FAST_CONST_CURRENT: 105*8c0984e5SSebastian Reichel case MAX77693_CHARGING_FAST_CONST_VOLTAGE: 106*8c0984e5SSebastian Reichel /* In high temp the charging current is reduced, but still charging */ 107*8c0984e5SSebastian Reichel case MAX77693_CHARGING_HIGH_TEMP: 108*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_CHARGE_TYPE_FAST; 109*8c0984e5SSebastian Reichel break; 110*8c0984e5SSebastian Reichel case MAX77693_CHARGING_DONE: 111*8c0984e5SSebastian Reichel case MAX77693_CHARGING_TIMER_EXPIRED: 112*8c0984e5SSebastian Reichel case MAX77693_CHARGING_THERMISTOR_SUSPEND: 113*8c0984e5SSebastian Reichel case MAX77693_CHARGING_OFF: 114*8c0984e5SSebastian Reichel case MAX77693_CHARGING_OVER_TEMP: 115*8c0984e5SSebastian Reichel case MAX77693_CHARGING_WATCHDOG_EXPIRED: 116*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 117*8c0984e5SSebastian Reichel break; 118*8c0984e5SSebastian Reichel case MAX77693_CHARGING_RESERVED: 119*8c0984e5SSebastian Reichel default: 120*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 121*8c0984e5SSebastian Reichel } 122*8c0984e5SSebastian Reichel 123*8c0984e5SSebastian Reichel return 0; 124*8c0984e5SSebastian Reichel } 125*8c0984e5SSebastian Reichel 126*8c0984e5SSebastian Reichel /* 127*8c0984e5SSebastian Reichel * Supported health statuses: 128*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_DEAD 129*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_GOOD 130*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_OVERVOLTAGE 131*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE 132*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_UNKNOWN 133*8c0984e5SSebastian Reichel * - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE 134*8c0984e5SSebastian Reichel */ 135*8c0984e5SSebastian Reichel static int max77693_get_battery_health(struct regmap *regmap, int *val) 136*8c0984e5SSebastian Reichel { 137*8c0984e5SSebastian Reichel int ret; 138*8c0984e5SSebastian Reichel unsigned int data; 139*8c0984e5SSebastian Reichel 140*8c0984e5SSebastian Reichel ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data); 141*8c0984e5SSebastian Reichel if (ret < 0) 142*8c0984e5SSebastian Reichel return ret; 143*8c0984e5SSebastian Reichel 144*8c0984e5SSebastian Reichel data &= CHG_DETAILS_01_BAT_MASK; 145*8c0984e5SSebastian Reichel data >>= CHG_DETAILS_01_BAT_SHIFT; 146*8c0984e5SSebastian Reichel 147*8c0984e5SSebastian Reichel switch (data) { 148*8c0984e5SSebastian Reichel case MAX77693_BATTERY_NOBAT: 149*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_DEAD; 150*8c0984e5SSebastian Reichel break; 151*8c0984e5SSebastian Reichel case MAX77693_BATTERY_PREQUALIFICATION: 152*8c0984e5SSebastian Reichel case MAX77693_BATTERY_GOOD: 153*8c0984e5SSebastian Reichel case MAX77693_BATTERY_LOWVOLTAGE: 154*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_GOOD; 155*8c0984e5SSebastian Reichel break; 156*8c0984e5SSebastian Reichel case MAX77693_BATTERY_TIMER_EXPIRED: 157*8c0984e5SSebastian Reichel /* 158*8c0984e5SSebastian Reichel * Took longer to charge than expected, charging suspended. 159*8c0984e5SSebastian Reichel * Damaged battery? 160*8c0984e5SSebastian Reichel */ 161*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 162*8c0984e5SSebastian Reichel break; 163*8c0984e5SSebastian Reichel case MAX77693_BATTERY_OVERVOLTAGE: 164*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 165*8c0984e5SSebastian Reichel break; 166*8c0984e5SSebastian Reichel case MAX77693_BATTERY_OVERCURRENT: 167*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 168*8c0984e5SSebastian Reichel break; 169*8c0984e5SSebastian Reichel case MAX77693_BATTERY_RESERVED: 170*8c0984e5SSebastian Reichel default: 171*8c0984e5SSebastian Reichel *val = POWER_SUPPLY_HEALTH_UNKNOWN; 172*8c0984e5SSebastian Reichel break; 173*8c0984e5SSebastian Reichel } 174*8c0984e5SSebastian Reichel 175*8c0984e5SSebastian Reichel return 0; 176*8c0984e5SSebastian Reichel } 177*8c0984e5SSebastian Reichel 178*8c0984e5SSebastian Reichel static int max77693_get_present(struct regmap *regmap, int *val) 179*8c0984e5SSebastian Reichel { 180*8c0984e5SSebastian Reichel unsigned int data; 181*8c0984e5SSebastian Reichel int ret; 182*8c0984e5SSebastian Reichel 183*8c0984e5SSebastian Reichel /* 184*8c0984e5SSebastian Reichel * Read CHG_INT_OK register. High DETBAT bit here should be 185*8c0984e5SSebastian Reichel * equal to value 0x0 in CHG_DETAILS_01/BAT field. 186*8c0984e5SSebastian Reichel */ 187*8c0984e5SSebastian Reichel ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data); 188*8c0984e5SSebastian Reichel if (ret < 0) 189*8c0984e5SSebastian Reichel return ret; 190*8c0984e5SSebastian Reichel 191*8c0984e5SSebastian Reichel *val = (data & CHG_INT_OK_DETBAT_MASK) ? 0 : 1; 192*8c0984e5SSebastian Reichel 193*8c0984e5SSebastian Reichel return 0; 194*8c0984e5SSebastian Reichel } 195*8c0984e5SSebastian Reichel 196*8c0984e5SSebastian Reichel static int max77693_get_online(struct regmap *regmap, int *val) 197*8c0984e5SSebastian Reichel { 198*8c0984e5SSebastian Reichel unsigned int data; 199*8c0984e5SSebastian Reichel int ret; 200*8c0984e5SSebastian Reichel 201*8c0984e5SSebastian Reichel ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data); 202*8c0984e5SSebastian Reichel if (ret < 0) 203*8c0984e5SSebastian Reichel return ret; 204*8c0984e5SSebastian Reichel 205*8c0984e5SSebastian Reichel *val = (data & CHG_INT_OK_CHGIN_MASK) ? 1 : 0; 206*8c0984e5SSebastian Reichel 207*8c0984e5SSebastian Reichel return 0; 208*8c0984e5SSebastian Reichel } 209*8c0984e5SSebastian Reichel 210*8c0984e5SSebastian Reichel static enum power_supply_property max77693_charger_props[] = { 211*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 212*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_TYPE, 213*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 214*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 215*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 216*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MODEL_NAME, 217*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 218*8c0984e5SSebastian Reichel }; 219*8c0984e5SSebastian Reichel 220*8c0984e5SSebastian Reichel static int max77693_charger_get_property(struct power_supply *psy, 221*8c0984e5SSebastian Reichel enum power_supply_property psp, 222*8c0984e5SSebastian Reichel union power_supply_propval *val) 223*8c0984e5SSebastian Reichel { 224*8c0984e5SSebastian Reichel struct max77693_charger *chg = power_supply_get_drvdata(psy); 225*8c0984e5SSebastian Reichel struct regmap *regmap = chg->max77693->regmap; 226*8c0984e5SSebastian Reichel int ret = 0; 227*8c0984e5SSebastian Reichel 228*8c0984e5SSebastian Reichel switch (psp) { 229*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 230*8c0984e5SSebastian Reichel ret = max77693_get_charger_state(regmap, &val->intval); 231*8c0984e5SSebastian Reichel break; 232*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_TYPE: 233*8c0984e5SSebastian Reichel ret = max77693_get_charge_type(regmap, &val->intval); 234*8c0984e5SSebastian Reichel break; 235*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 236*8c0984e5SSebastian Reichel ret = max77693_get_battery_health(regmap, &val->intval); 237*8c0984e5SSebastian Reichel break; 238*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 239*8c0984e5SSebastian Reichel ret = max77693_get_present(regmap, &val->intval); 240*8c0984e5SSebastian Reichel break; 241*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 242*8c0984e5SSebastian Reichel ret = max77693_get_online(regmap, &val->intval); 243*8c0984e5SSebastian Reichel break; 244*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MODEL_NAME: 245*8c0984e5SSebastian Reichel val->strval = max77693_charger_model; 246*8c0984e5SSebastian Reichel break; 247*8c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 248*8c0984e5SSebastian Reichel val->strval = max77693_charger_manufacturer; 249*8c0984e5SSebastian Reichel break; 250*8c0984e5SSebastian Reichel default: 251*8c0984e5SSebastian Reichel return -EINVAL; 252*8c0984e5SSebastian Reichel } 253*8c0984e5SSebastian Reichel 254*8c0984e5SSebastian Reichel return ret; 255*8c0984e5SSebastian Reichel } 256*8c0984e5SSebastian Reichel 257*8c0984e5SSebastian Reichel static const struct power_supply_desc max77693_charger_desc = { 258*8c0984e5SSebastian Reichel .name = MAX77693_CHARGER_NAME, 259*8c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_BATTERY, 260*8c0984e5SSebastian Reichel .properties = max77693_charger_props, 261*8c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(max77693_charger_props), 262*8c0984e5SSebastian Reichel .get_property = max77693_charger_get_property, 263*8c0984e5SSebastian Reichel }; 264*8c0984e5SSebastian Reichel 265*8c0984e5SSebastian Reichel static ssize_t device_attr_store(struct device *dev, 266*8c0984e5SSebastian Reichel struct device_attribute *attr, const char *buf, size_t count, 267*8c0984e5SSebastian Reichel int (*fn)(struct max77693_charger *, unsigned long)) 268*8c0984e5SSebastian Reichel { 269*8c0984e5SSebastian Reichel struct max77693_charger *chg = dev_get_drvdata(dev); 270*8c0984e5SSebastian Reichel unsigned long val; 271*8c0984e5SSebastian Reichel int ret; 272*8c0984e5SSebastian Reichel 273*8c0984e5SSebastian Reichel ret = kstrtoul(buf, 10, &val); 274*8c0984e5SSebastian Reichel if (ret) 275*8c0984e5SSebastian Reichel return ret; 276*8c0984e5SSebastian Reichel 277*8c0984e5SSebastian Reichel ret = fn(chg, val); 278*8c0984e5SSebastian Reichel if (ret) 279*8c0984e5SSebastian Reichel return ret; 280*8c0984e5SSebastian Reichel 281*8c0984e5SSebastian Reichel return count; 282*8c0984e5SSebastian Reichel } 283*8c0984e5SSebastian Reichel 284*8c0984e5SSebastian Reichel static ssize_t fast_charge_timer_show(struct device *dev, 285*8c0984e5SSebastian Reichel struct device_attribute *attr, char *buf) 286*8c0984e5SSebastian Reichel { 287*8c0984e5SSebastian Reichel struct max77693_charger *chg = dev_get_drvdata(dev); 288*8c0984e5SSebastian Reichel unsigned int data, val; 289*8c0984e5SSebastian Reichel int ret; 290*8c0984e5SSebastian Reichel 291*8c0984e5SSebastian Reichel ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_01, 292*8c0984e5SSebastian Reichel &data); 293*8c0984e5SSebastian Reichel if (ret < 0) 294*8c0984e5SSebastian Reichel return ret; 295*8c0984e5SSebastian Reichel 296*8c0984e5SSebastian Reichel data &= CHG_CNFG_01_FCHGTIME_MASK; 297*8c0984e5SSebastian Reichel data >>= CHG_CNFG_01_FCHGTIME_SHIFT; 298*8c0984e5SSebastian Reichel switch (data) { 299*8c0984e5SSebastian Reichel case 0x1 ... 0x7: 300*8c0984e5SSebastian Reichel /* Starting from 4 hours, step by 2 hours */ 301*8c0984e5SSebastian Reichel val = 4 + (data - 1) * 2; 302*8c0984e5SSebastian Reichel break; 303*8c0984e5SSebastian Reichel case 0x0: 304*8c0984e5SSebastian Reichel default: 305*8c0984e5SSebastian Reichel val = 0; 306*8c0984e5SSebastian Reichel break; 307*8c0984e5SSebastian Reichel } 308*8c0984e5SSebastian Reichel 309*8c0984e5SSebastian Reichel return scnprintf(buf, PAGE_SIZE, "%u\n", val); 310*8c0984e5SSebastian Reichel } 311*8c0984e5SSebastian Reichel 312*8c0984e5SSebastian Reichel static int max77693_set_fast_charge_timer(struct max77693_charger *chg, 313*8c0984e5SSebastian Reichel unsigned long hours) 314*8c0984e5SSebastian Reichel { 315*8c0984e5SSebastian Reichel unsigned int data; 316*8c0984e5SSebastian Reichel 317*8c0984e5SSebastian Reichel /* 318*8c0984e5SSebastian Reichel * 0x00 - disable 319*8c0984e5SSebastian Reichel * 0x01 - 4h 320*8c0984e5SSebastian Reichel * 0x02 - 6h 321*8c0984e5SSebastian Reichel * ... 322*8c0984e5SSebastian Reichel * 0x07 - 16h 323*8c0984e5SSebastian Reichel * Round down odd values. 324*8c0984e5SSebastian Reichel */ 325*8c0984e5SSebastian Reichel switch (hours) { 326*8c0984e5SSebastian Reichel case 4 ... 16: 327*8c0984e5SSebastian Reichel data = (hours - 4) / 2 + 1; 328*8c0984e5SSebastian Reichel break; 329*8c0984e5SSebastian Reichel case 0: 330*8c0984e5SSebastian Reichel /* Disable */ 331*8c0984e5SSebastian Reichel data = 0; 332*8c0984e5SSebastian Reichel break; 333*8c0984e5SSebastian Reichel default: 334*8c0984e5SSebastian Reichel return -EINVAL; 335*8c0984e5SSebastian Reichel } 336*8c0984e5SSebastian Reichel data <<= CHG_CNFG_01_FCHGTIME_SHIFT; 337*8c0984e5SSebastian Reichel 338*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 339*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_01, 340*8c0984e5SSebastian Reichel CHG_CNFG_01_FCHGTIME_MASK, data); 341*8c0984e5SSebastian Reichel } 342*8c0984e5SSebastian Reichel 343*8c0984e5SSebastian Reichel static ssize_t fast_charge_timer_store(struct device *dev, 344*8c0984e5SSebastian Reichel struct device_attribute *attr, const char *buf, size_t count) 345*8c0984e5SSebastian Reichel { 346*8c0984e5SSebastian Reichel return device_attr_store(dev, attr, buf, count, 347*8c0984e5SSebastian Reichel max77693_set_fast_charge_timer); 348*8c0984e5SSebastian Reichel } 349*8c0984e5SSebastian Reichel 350*8c0984e5SSebastian Reichel static ssize_t top_off_threshold_current_show(struct device *dev, 351*8c0984e5SSebastian Reichel struct device_attribute *attr, char *buf) 352*8c0984e5SSebastian Reichel { 353*8c0984e5SSebastian Reichel struct max77693_charger *chg = dev_get_drvdata(dev); 354*8c0984e5SSebastian Reichel unsigned int data, val; 355*8c0984e5SSebastian Reichel int ret; 356*8c0984e5SSebastian Reichel 357*8c0984e5SSebastian Reichel ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03, 358*8c0984e5SSebastian Reichel &data); 359*8c0984e5SSebastian Reichel if (ret < 0) 360*8c0984e5SSebastian Reichel return ret; 361*8c0984e5SSebastian Reichel 362*8c0984e5SSebastian Reichel data &= CHG_CNFG_03_TOITH_MASK; 363*8c0984e5SSebastian Reichel data >>= CHG_CNFG_03_TOITH_SHIFT; 364*8c0984e5SSebastian Reichel 365*8c0984e5SSebastian Reichel if (data <= 0x04) 366*8c0984e5SSebastian Reichel val = 100000 + data * 25000; 367*8c0984e5SSebastian Reichel else 368*8c0984e5SSebastian Reichel val = data * 50000; 369*8c0984e5SSebastian Reichel 370*8c0984e5SSebastian Reichel return scnprintf(buf, PAGE_SIZE, "%u\n", val); 371*8c0984e5SSebastian Reichel } 372*8c0984e5SSebastian Reichel 373*8c0984e5SSebastian Reichel static int max77693_set_top_off_threshold_current(struct max77693_charger *chg, 374*8c0984e5SSebastian Reichel unsigned long uamp) 375*8c0984e5SSebastian Reichel { 376*8c0984e5SSebastian Reichel unsigned int data; 377*8c0984e5SSebastian Reichel 378*8c0984e5SSebastian Reichel if (uamp < 100000 || uamp > 350000) 379*8c0984e5SSebastian Reichel return -EINVAL; 380*8c0984e5SSebastian Reichel 381*8c0984e5SSebastian Reichel if (uamp <= 200000) 382*8c0984e5SSebastian Reichel data = (uamp - 100000) / 25000; 383*8c0984e5SSebastian Reichel else 384*8c0984e5SSebastian Reichel /* (200000, 350000> */ 385*8c0984e5SSebastian Reichel data = uamp / 50000; 386*8c0984e5SSebastian Reichel 387*8c0984e5SSebastian Reichel data <<= CHG_CNFG_03_TOITH_SHIFT; 388*8c0984e5SSebastian Reichel 389*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 390*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_03, 391*8c0984e5SSebastian Reichel CHG_CNFG_03_TOITH_MASK, data); 392*8c0984e5SSebastian Reichel } 393*8c0984e5SSebastian Reichel 394*8c0984e5SSebastian Reichel static ssize_t top_off_threshold_current_store(struct device *dev, 395*8c0984e5SSebastian Reichel struct device_attribute *attr, const char *buf, size_t count) 396*8c0984e5SSebastian Reichel { 397*8c0984e5SSebastian Reichel return device_attr_store(dev, attr, buf, count, 398*8c0984e5SSebastian Reichel max77693_set_top_off_threshold_current); 399*8c0984e5SSebastian Reichel } 400*8c0984e5SSebastian Reichel 401*8c0984e5SSebastian Reichel static ssize_t top_off_timer_show(struct device *dev, 402*8c0984e5SSebastian Reichel struct device_attribute *attr, char *buf) 403*8c0984e5SSebastian Reichel { 404*8c0984e5SSebastian Reichel struct max77693_charger *chg = dev_get_drvdata(dev); 405*8c0984e5SSebastian Reichel unsigned int data, val; 406*8c0984e5SSebastian Reichel int ret; 407*8c0984e5SSebastian Reichel 408*8c0984e5SSebastian Reichel ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03, 409*8c0984e5SSebastian Reichel &data); 410*8c0984e5SSebastian Reichel if (ret < 0) 411*8c0984e5SSebastian Reichel return ret; 412*8c0984e5SSebastian Reichel 413*8c0984e5SSebastian Reichel data &= CHG_CNFG_03_TOTIME_MASK; 414*8c0984e5SSebastian Reichel data >>= CHG_CNFG_03_TOTIME_SHIFT; 415*8c0984e5SSebastian Reichel 416*8c0984e5SSebastian Reichel val = data * 10; 417*8c0984e5SSebastian Reichel 418*8c0984e5SSebastian Reichel return scnprintf(buf, PAGE_SIZE, "%u\n", val); 419*8c0984e5SSebastian Reichel } 420*8c0984e5SSebastian Reichel 421*8c0984e5SSebastian Reichel static int max77693_set_top_off_timer(struct max77693_charger *chg, 422*8c0984e5SSebastian Reichel unsigned long minutes) 423*8c0984e5SSebastian Reichel { 424*8c0984e5SSebastian Reichel unsigned int data; 425*8c0984e5SSebastian Reichel 426*8c0984e5SSebastian Reichel if (minutes > 70) 427*8c0984e5SSebastian Reichel return -EINVAL; 428*8c0984e5SSebastian Reichel 429*8c0984e5SSebastian Reichel data = minutes / 10; 430*8c0984e5SSebastian Reichel data <<= CHG_CNFG_03_TOTIME_SHIFT; 431*8c0984e5SSebastian Reichel 432*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 433*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_03, 434*8c0984e5SSebastian Reichel CHG_CNFG_03_TOTIME_MASK, data); 435*8c0984e5SSebastian Reichel } 436*8c0984e5SSebastian Reichel 437*8c0984e5SSebastian Reichel static ssize_t top_off_timer_store(struct device *dev, 438*8c0984e5SSebastian Reichel struct device_attribute *attr, const char *buf, size_t count) 439*8c0984e5SSebastian Reichel { 440*8c0984e5SSebastian Reichel return device_attr_store(dev, attr, buf, count, 441*8c0984e5SSebastian Reichel max77693_set_top_off_timer); 442*8c0984e5SSebastian Reichel } 443*8c0984e5SSebastian Reichel 444*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(fast_charge_timer); 445*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(top_off_threshold_current); 446*8c0984e5SSebastian Reichel static DEVICE_ATTR_RW(top_off_timer); 447*8c0984e5SSebastian Reichel 448*8c0984e5SSebastian Reichel static int max77693_set_constant_volt(struct max77693_charger *chg, 449*8c0984e5SSebastian Reichel unsigned int uvolt) 450*8c0984e5SSebastian Reichel { 451*8c0984e5SSebastian Reichel unsigned int data; 452*8c0984e5SSebastian Reichel 453*8c0984e5SSebastian Reichel /* 454*8c0984e5SSebastian Reichel * 0x00 - 3.650 V 455*8c0984e5SSebastian Reichel * 0x01 - 3.675 V 456*8c0984e5SSebastian Reichel * ... 457*8c0984e5SSebastian Reichel * 0x1b - 4.325 V 458*8c0984e5SSebastian Reichel * 0x1c - 4.340 V 459*8c0984e5SSebastian Reichel * 0x1d - 4.350 V 460*8c0984e5SSebastian Reichel * 0x1e - 4.375 V 461*8c0984e5SSebastian Reichel * 0x1f - 4.400 V 462*8c0984e5SSebastian Reichel */ 463*8c0984e5SSebastian Reichel if (uvolt >= 3650000 && uvolt < 4340000) 464*8c0984e5SSebastian Reichel data = (uvolt - 3650000) / 25000; 465*8c0984e5SSebastian Reichel else if (uvolt >= 4340000 && uvolt < 4350000) 466*8c0984e5SSebastian Reichel data = 0x1c; 467*8c0984e5SSebastian Reichel else if (uvolt >= 4350000 && uvolt <= 4400000) 468*8c0984e5SSebastian Reichel data = 0x1d + (uvolt - 4350000) / 25000; 469*8c0984e5SSebastian Reichel else { 470*8c0984e5SSebastian Reichel dev_err(chg->dev, "Wrong value for charging constant voltage\n"); 471*8c0984e5SSebastian Reichel return -EINVAL; 472*8c0984e5SSebastian Reichel } 473*8c0984e5SSebastian Reichel 474*8c0984e5SSebastian Reichel data <<= CHG_CNFG_04_CHGCVPRM_SHIFT; 475*8c0984e5SSebastian Reichel 476*8c0984e5SSebastian Reichel dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt, 477*8c0984e5SSebastian Reichel data); 478*8c0984e5SSebastian Reichel 479*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 480*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_04, 481*8c0984e5SSebastian Reichel CHG_CNFG_04_CHGCVPRM_MASK, data); 482*8c0984e5SSebastian Reichel } 483*8c0984e5SSebastian Reichel 484*8c0984e5SSebastian Reichel static int max77693_set_min_system_volt(struct max77693_charger *chg, 485*8c0984e5SSebastian Reichel unsigned int uvolt) 486*8c0984e5SSebastian Reichel { 487*8c0984e5SSebastian Reichel unsigned int data; 488*8c0984e5SSebastian Reichel 489*8c0984e5SSebastian Reichel if (uvolt < 3000000 || uvolt > 3700000) { 490*8c0984e5SSebastian Reichel dev_err(chg->dev, "Wrong value for minimum system regulation voltage\n"); 491*8c0984e5SSebastian Reichel return -EINVAL; 492*8c0984e5SSebastian Reichel } 493*8c0984e5SSebastian Reichel 494*8c0984e5SSebastian Reichel data = (uvolt - 3000000) / 100000; 495*8c0984e5SSebastian Reichel 496*8c0984e5SSebastian Reichel data <<= CHG_CNFG_04_MINVSYS_SHIFT; 497*8c0984e5SSebastian Reichel 498*8c0984e5SSebastian Reichel dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n", 499*8c0984e5SSebastian Reichel uvolt, data); 500*8c0984e5SSebastian Reichel 501*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 502*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_04, 503*8c0984e5SSebastian Reichel CHG_CNFG_04_MINVSYS_MASK, data); 504*8c0984e5SSebastian Reichel } 505*8c0984e5SSebastian Reichel 506*8c0984e5SSebastian Reichel static int max77693_set_thermal_regulation_temp(struct max77693_charger *chg, 507*8c0984e5SSebastian Reichel unsigned int cels) 508*8c0984e5SSebastian Reichel { 509*8c0984e5SSebastian Reichel unsigned int data; 510*8c0984e5SSebastian Reichel 511*8c0984e5SSebastian Reichel switch (cels) { 512*8c0984e5SSebastian Reichel case 70: 513*8c0984e5SSebastian Reichel case 85: 514*8c0984e5SSebastian Reichel case 100: 515*8c0984e5SSebastian Reichel case 115: 516*8c0984e5SSebastian Reichel data = (cels - 70) / 15; 517*8c0984e5SSebastian Reichel break; 518*8c0984e5SSebastian Reichel default: 519*8c0984e5SSebastian Reichel dev_err(chg->dev, "Wrong value for thermal regulation loop temperature\n"); 520*8c0984e5SSebastian Reichel return -EINVAL; 521*8c0984e5SSebastian Reichel } 522*8c0984e5SSebastian Reichel 523*8c0984e5SSebastian Reichel data <<= CHG_CNFG_07_REGTEMP_SHIFT; 524*8c0984e5SSebastian Reichel 525*8c0984e5SSebastian Reichel dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n", 526*8c0984e5SSebastian Reichel cels, data); 527*8c0984e5SSebastian Reichel 528*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 529*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_07, 530*8c0984e5SSebastian Reichel CHG_CNFG_07_REGTEMP_MASK, data); 531*8c0984e5SSebastian Reichel } 532*8c0984e5SSebastian Reichel 533*8c0984e5SSebastian Reichel static int max77693_set_batttery_overcurrent(struct max77693_charger *chg, 534*8c0984e5SSebastian Reichel unsigned int uamp) 535*8c0984e5SSebastian Reichel { 536*8c0984e5SSebastian Reichel unsigned int data; 537*8c0984e5SSebastian Reichel 538*8c0984e5SSebastian Reichel if (uamp && (uamp < 2000000 || uamp > 3500000)) { 539*8c0984e5SSebastian Reichel dev_err(chg->dev, "Wrong value for battery overcurrent\n"); 540*8c0984e5SSebastian Reichel return -EINVAL; 541*8c0984e5SSebastian Reichel } 542*8c0984e5SSebastian Reichel 543*8c0984e5SSebastian Reichel if (uamp) 544*8c0984e5SSebastian Reichel data = ((uamp - 2000000) / 250000) + 1; 545*8c0984e5SSebastian Reichel else 546*8c0984e5SSebastian Reichel data = 0; /* disable */ 547*8c0984e5SSebastian Reichel 548*8c0984e5SSebastian Reichel data <<= CHG_CNFG_12_B2SOVRC_SHIFT; 549*8c0984e5SSebastian Reichel 550*8c0984e5SSebastian Reichel dev_dbg(chg->dev, "Battery overcurrent: %u (0x%x)\n", uamp, data); 551*8c0984e5SSebastian Reichel 552*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 553*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_12, 554*8c0984e5SSebastian Reichel CHG_CNFG_12_B2SOVRC_MASK, data); 555*8c0984e5SSebastian Reichel } 556*8c0984e5SSebastian Reichel 557*8c0984e5SSebastian Reichel static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg, 558*8c0984e5SSebastian Reichel unsigned int uvolt) 559*8c0984e5SSebastian Reichel { 560*8c0984e5SSebastian Reichel unsigned int data; 561*8c0984e5SSebastian Reichel 562*8c0984e5SSebastian Reichel switch (uvolt) { 563*8c0984e5SSebastian Reichel case 4300000: 564*8c0984e5SSebastian Reichel data = 0x0; 565*8c0984e5SSebastian Reichel break; 566*8c0984e5SSebastian Reichel case 4700000: 567*8c0984e5SSebastian Reichel case 4800000: 568*8c0984e5SSebastian Reichel case 4900000: 569*8c0984e5SSebastian Reichel data = (uvolt - 4700000) / 100000; 570*8c0984e5SSebastian Reichel default: 571*8c0984e5SSebastian Reichel dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n"); 572*8c0984e5SSebastian Reichel return -EINVAL; 573*8c0984e5SSebastian Reichel } 574*8c0984e5SSebastian Reichel 575*8c0984e5SSebastian Reichel data <<= CHG_CNFG_12_VCHGINREG_SHIFT; 576*8c0984e5SSebastian Reichel 577*8c0984e5SSebastian Reichel dev_dbg(chg->dev, "Charge input voltage regulation threshold: %u (0x%x)\n", 578*8c0984e5SSebastian Reichel uvolt, data); 579*8c0984e5SSebastian Reichel 580*8c0984e5SSebastian Reichel return regmap_update_bits(chg->max77693->regmap, 581*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_12, 582*8c0984e5SSebastian Reichel CHG_CNFG_12_VCHGINREG_MASK, data); 583*8c0984e5SSebastian Reichel } 584*8c0984e5SSebastian Reichel 585*8c0984e5SSebastian Reichel /* 586*8c0984e5SSebastian Reichel * Sets charger registers to proper and safe default values. 587*8c0984e5SSebastian Reichel */ 588*8c0984e5SSebastian Reichel static int max77693_reg_init(struct max77693_charger *chg) 589*8c0984e5SSebastian Reichel { 590*8c0984e5SSebastian Reichel int ret; 591*8c0984e5SSebastian Reichel unsigned int data; 592*8c0984e5SSebastian Reichel 593*8c0984e5SSebastian Reichel /* Unlock charger register protection */ 594*8c0984e5SSebastian Reichel data = (0x3 << CHG_CNFG_06_CHGPROT_SHIFT); 595*8c0984e5SSebastian Reichel ret = regmap_update_bits(chg->max77693->regmap, 596*8c0984e5SSebastian Reichel MAX77693_CHG_REG_CHG_CNFG_06, 597*8c0984e5SSebastian Reichel CHG_CNFG_06_CHGPROT_MASK, data); 598*8c0984e5SSebastian Reichel if (ret) { 599*8c0984e5SSebastian Reichel dev_err(chg->dev, "Error unlocking registers: %d\n", ret); 600*8c0984e5SSebastian Reichel return ret; 601*8c0984e5SSebastian Reichel } 602*8c0984e5SSebastian Reichel 603*8c0984e5SSebastian Reichel ret = max77693_set_fast_charge_timer(chg, DEFAULT_FAST_CHARGE_TIMER); 604*8c0984e5SSebastian Reichel if (ret) 605*8c0984e5SSebastian Reichel return ret; 606*8c0984e5SSebastian Reichel 607*8c0984e5SSebastian Reichel ret = max77693_set_top_off_threshold_current(chg, 608*8c0984e5SSebastian Reichel DEFAULT_TOP_OFF_THRESHOLD_CURRENT); 609*8c0984e5SSebastian Reichel if (ret) 610*8c0984e5SSebastian Reichel return ret; 611*8c0984e5SSebastian Reichel 612*8c0984e5SSebastian Reichel ret = max77693_set_top_off_timer(chg, DEFAULT_TOP_OFF_TIMER); 613*8c0984e5SSebastian Reichel if (ret) 614*8c0984e5SSebastian Reichel return ret; 615*8c0984e5SSebastian Reichel 616*8c0984e5SSebastian Reichel ret = max77693_set_constant_volt(chg, chg->constant_volt); 617*8c0984e5SSebastian Reichel if (ret) 618*8c0984e5SSebastian Reichel return ret; 619*8c0984e5SSebastian Reichel 620*8c0984e5SSebastian Reichel ret = max77693_set_min_system_volt(chg, chg->min_system_volt); 621*8c0984e5SSebastian Reichel if (ret) 622*8c0984e5SSebastian Reichel return ret; 623*8c0984e5SSebastian Reichel 624*8c0984e5SSebastian Reichel ret = max77693_set_thermal_regulation_temp(chg, 625*8c0984e5SSebastian Reichel chg->thermal_regulation_temp); 626*8c0984e5SSebastian Reichel if (ret) 627*8c0984e5SSebastian Reichel return ret; 628*8c0984e5SSebastian Reichel 629*8c0984e5SSebastian Reichel ret = max77693_set_batttery_overcurrent(chg, chg->batttery_overcurrent); 630*8c0984e5SSebastian Reichel if (ret) 631*8c0984e5SSebastian Reichel return ret; 632*8c0984e5SSebastian Reichel 633*8c0984e5SSebastian Reichel return max77693_set_charge_input_threshold_volt(chg, 634*8c0984e5SSebastian Reichel chg->charge_input_threshold_volt); 635*8c0984e5SSebastian Reichel } 636*8c0984e5SSebastian Reichel 637*8c0984e5SSebastian Reichel #ifdef CONFIG_OF 638*8c0984e5SSebastian Reichel static int max77693_dt_init(struct device *dev, struct max77693_charger *chg) 639*8c0984e5SSebastian Reichel { 640*8c0984e5SSebastian Reichel struct device_node *np = dev->of_node; 641*8c0984e5SSebastian Reichel 642*8c0984e5SSebastian Reichel if (!np) { 643*8c0984e5SSebastian Reichel dev_err(dev, "no charger OF node\n"); 644*8c0984e5SSebastian Reichel return -EINVAL; 645*8c0984e5SSebastian Reichel } 646*8c0984e5SSebastian Reichel 647*8c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,constant-microvolt", 648*8c0984e5SSebastian Reichel &chg->constant_volt)) 649*8c0984e5SSebastian Reichel chg->constant_volt = DEFAULT_CONSTANT_VOLT; 650*8c0984e5SSebastian Reichel 651*8c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,min-system-microvolt", 652*8c0984e5SSebastian Reichel &chg->min_system_volt)) 653*8c0984e5SSebastian Reichel chg->min_system_volt = DEFAULT_MIN_SYSTEM_VOLT; 654*8c0984e5SSebastian Reichel 655*8c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,thermal-regulation-celsius", 656*8c0984e5SSebastian Reichel &chg->thermal_regulation_temp)) 657*8c0984e5SSebastian Reichel chg->thermal_regulation_temp = DEFAULT_THERMAL_REGULATION_TEMP; 658*8c0984e5SSebastian Reichel 659*8c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,battery-overcurrent-microamp", 660*8c0984e5SSebastian Reichel &chg->batttery_overcurrent)) 661*8c0984e5SSebastian Reichel chg->batttery_overcurrent = DEFAULT_BATTERY_OVERCURRENT; 662*8c0984e5SSebastian Reichel 663*8c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,charge-input-threshold-microvolt", 664*8c0984e5SSebastian Reichel &chg->charge_input_threshold_volt)) 665*8c0984e5SSebastian Reichel chg->charge_input_threshold_volt = 666*8c0984e5SSebastian Reichel DEFAULT_CHARGER_INPUT_THRESHOLD_VOLT; 667*8c0984e5SSebastian Reichel 668*8c0984e5SSebastian Reichel return 0; 669*8c0984e5SSebastian Reichel } 670*8c0984e5SSebastian Reichel #else /* CONFIG_OF */ 671*8c0984e5SSebastian Reichel static int max77693_dt_init(struct device *dev, struct max77693_charger *chg) 672*8c0984e5SSebastian Reichel { 673*8c0984e5SSebastian Reichel return 0; 674*8c0984e5SSebastian Reichel } 675*8c0984e5SSebastian Reichel #endif /* CONFIG_OF */ 676*8c0984e5SSebastian Reichel 677*8c0984e5SSebastian Reichel static int max77693_charger_probe(struct platform_device *pdev) 678*8c0984e5SSebastian Reichel { 679*8c0984e5SSebastian Reichel struct max77693_charger *chg; 680*8c0984e5SSebastian Reichel struct power_supply_config psy_cfg = {}; 681*8c0984e5SSebastian Reichel struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); 682*8c0984e5SSebastian Reichel int ret; 683*8c0984e5SSebastian Reichel 684*8c0984e5SSebastian Reichel chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); 685*8c0984e5SSebastian Reichel if (!chg) 686*8c0984e5SSebastian Reichel return -ENOMEM; 687*8c0984e5SSebastian Reichel 688*8c0984e5SSebastian Reichel platform_set_drvdata(pdev, chg); 689*8c0984e5SSebastian Reichel chg->dev = &pdev->dev; 690*8c0984e5SSebastian Reichel chg->max77693 = max77693; 691*8c0984e5SSebastian Reichel 692*8c0984e5SSebastian Reichel ret = max77693_dt_init(&pdev->dev, chg); 693*8c0984e5SSebastian Reichel if (ret) 694*8c0984e5SSebastian Reichel return ret; 695*8c0984e5SSebastian Reichel 696*8c0984e5SSebastian Reichel ret = max77693_reg_init(chg); 697*8c0984e5SSebastian Reichel if (ret) 698*8c0984e5SSebastian Reichel return ret; 699*8c0984e5SSebastian Reichel 700*8c0984e5SSebastian Reichel psy_cfg.drv_data = chg; 701*8c0984e5SSebastian Reichel 702*8c0984e5SSebastian Reichel ret = device_create_file(&pdev->dev, &dev_attr_fast_charge_timer); 703*8c0984e5SSebastian Reichel if (ret) { 704*8c0984e5SSebastian Reichel dev_err(&pdev->dev, "failed: create fast charge timer sysfs entry\n"); 705*8c0984e5SSebastian Reichel goto err; 706*8c0984e5SSebastian Reichel } 707*8c0984e5SSebastian Reichel 708*8c0984e5SSebastian Reichel ret = device_create_file(&pdev->dev, 709*8c0984e5SSebastian Reichel &dev_attr_top_off_threshold_current); 710*8c0984e5SSebastian Reichel if (ret) { 711*8c0984e5SSebastian Reichel dev_err(&pdev->dev, "failed: create top off current sysfs entry\n"); 712*8c0984e5SSebastian Reichel goto err; 713*8c0984e5SSebastian Reichel } 714*8c0984e5SSebastian Reichel 715*8c0984e5SSebastian Reichel ret = device_create_file(&pdev->dev, &dev_attr_top_off_timer); 716*8c0984e5SSebastian Reichel if (ret) { 717*8c0984e5SSebastian Reichel dev_err(&pdev->dev, "failed: create top off timer sysfs entry\n"); 718*8c0984e5SSebastian Reichel goto err; 719*8c0984e5SSebastian Reichel } 720*8c0984e5SSebastian Reichel 721*8c0984e5SSebastian Reichel chg->charger = power_supply_register(&pdev->dev, 722*8c0984e5SSebastian Reichel &max77693_charger_desc, 723*8c0984e5SSebastian Reichel &psy_cfg); 724*8c0984e5SSebastian Reichel if (IS_ERR(chg->charger)) { 725*8c0984e5SSebastian Reichel dev_err(&pdev->dev, "failed: power supply register\n"); 726*8c0984e5SSebastian Reichel ret = PTR_ERR(chg->charger); 727*8c0984e5SSebastian Reichel goto err; 728*8c0984e5SSebastian Reichel } 729*8c0984e5SSebastian Reichel 730*8c0984e5SSebastian Reichel return 0; 731*8c0984e5SSebastian Reichel 732*8c0984e5SSebastian Reichel err: 733*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_top_off_timer); 734*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current); 735*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); 736*8c0984e5SSebastian Reichel 737*8c0984e5SSebastian Reichel return ret; 738*8c0984e5SSebastian Reichel } 739*8c0984e5SSebastian Reichel 740*8c0984e5SSebastian Reichel static int max77693_charger_remove(struct platform_device *pdev) 741*8c0984e5SSebastian Reichel { 742*8c0984e5SSebastian Reichel struct max77693_charger *chg = platform_get_drvdata(pdev); 743*8c0984e5SSebastian Reichel 744*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_top_off_timer); 745*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current); 746*8c0984e5SSebastian Reichel device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); 747*8c0984e5SSebastian Reichel 748*8c0984e5SSebastian Reichel power_supply_unregister(chg->charger); 749*8c0984e5SSebastian Reichel 750*8c0984e5SSebastian Reichel return 0; 751*8c0984e5SSebastian Reichel } 752*8c0984e5SSebastian Reichel 753*8c0984e5SSebastian Reichel static const struct platform_device_id max77693_charger_id[] = { 754*8c0984e5SSebastian Reichel { "max77693-charger", 0, }, 755*8c0984e5SSebastian Reichel { } 756*8c0984e5SSebastian Reichel }; 757*8c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(platform, max77693_charger_id); 758*8c0984e5SSebastian Reichel 759*8c0984e5SSebastian Reichel static struct platform_driver max77693_charger_driver = { 760*8c0984e5SSebastian Reichel .driver = { 761*8c0984e5SSebastian Reichel .name = "max77693-charger", 762*8c0984e5SSebastian Reichel }, 763*8c0984e5SSebastian Reichel .probe = max77693_charger_probe, 764*8c0984e5SSebastian Reichel .remove = max77693_charger_remove, 765*8c0984e5SSebastian Reichel .id_table = max77693_charger_id, 766*8c0984e5SSebastian Reichel }; 767*8c0984e5SSebastian Reichel module_platform_driver(max77693_charger_driver); 768*8c0984e5SSebastian Reichel 769*8c0984e5SSebastian Reichel MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); 770*8c0984e5SSebastian Reichel MODULE_DESCRIPTION("Maxim 77693 charger driver"); 771*8c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 772