Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Battery charger driver for Dialog Semiconductor DA9030
0004  *
0005  * Copyright (C) 2008 Compulab, Ltd.
0006  *  Mike Rapoport <mike@compulab.co.il>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011 #include <linux/init.h>
0012 #include <linux/types.h>
0013 #include <linux/device.h>
0014 #include <linux/workqueue.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/power_supply.h>
0018 #include <linux/mfd/da903x.h>
0019 
0020 #include <linux/debugfs.h>
0021 #include <linux/seq_file.h>
0022 #include <linux/notifier.h>
0023 
0024 #define DA9030_FAULT_LOG        0x0a
0025 #define DA9030_FAULT_LOG_OVER_TEMP  (1 << 7)
0026 #define DA9030_FAULT_LOG_VBAT_OVER  (1 << 4)
0027 
0028 #define DA9030_CHARGE_CONTROL       0x28
0029 #define DA9030_CHRG_CHARGER_ENABLE  (1 << 7)
0030 
0031 #define DA9030_ADC_MAN_CONTROL      0x30
0032 #define DA9030_ADC_TBATREF_ENABLE   (1 << 5)
0033 #define DA9030_ADC_LDO_INT_ENABLE   (1 << 4)
0034 
0035 #define DA9030_ADC_AUTO_CONTROL     0x31
0036 #define DA9030_ADC_TBAT_ENABLE      (1 << 5)
0037 #define DA9030_ADC_VBAT_IN_TXON     (1 << 4)
0038 #define DA9030_ADC_VCH_ENABLE       (1 << 3)
0039 #define DA9030_ADC_ICH_ENABLE       (1 << 2)
0040 #define DA9030_ADC_VBAT_ENABLE      (1 << 1)
0041 #define DA9030_ADC_AUTO_SLEEP_ENABLE    (1 << 0)
0042 
0043 #define DA9030_VBATMON      0x32
0044 #define DA9030_VBATMONTXON  0x33
0045 #define DA9030_TBATHIGHP    0x34
0046 #define DA9030_TBATHIGHN    0x35
0047 #define DA9030_TBATLOW      0x36
0048 
0049 #define DA9030_VBAT_RES     0x41
0050 #define DA9030_VBATMIN_RES  0x42
0051 #define DA9030_VBATMINTXON_RES  0x43
0052 #define DA9030_ICHMAX_RES   0x44
0053 #define DA9030_ICHMIN_RES   0x45
0054 #define DA9030_ICHAVERAGE_RES   0x46
0055 #define DA9030_VCHMAX_RES   0x47
0056 #define DA9030_VCHMIN_RES   0x48
0057 #define DA9030_TBAT_RES     0x49
0058 
0059 struct da9030_adc_res {
0060     uint8_t vbat_res;
0061     uint8_t vbatmin_res;
0062     uint8_t vbatmintxon;
0063     uint8_t ichmax_res;
0064     uint8_t ichmin_res;
0065     uint8_t ichaverage_res;
0066     uint8_t vchmax_res;
0067     uint8_t vchmin_res;
0068     uint8_t tbat_res;
0069     uint8_t adc_in4_res;
0070     uint8_t adc_in5_res;
0071 };
0072 
0073 struct da9030_battery_thresholds {
0074     int tbat_low;
0075     int tbat_high;
0076     int tbat_restart;
0077 
0078     int vbat_low;
0079     int vbat_crit;
0080     int vbat_charge_start;
0081     int vbat_charge_stop;
0082     int vbat_charge_restart;
0083 
0084     int vcharge_min;
0085     int vcharge_max;
0086 };
0087 
0088 struct da9030_charger {
0089     struct power_supply *psy;
0090     struct power_supply_desc psy_desc;
0091 
0092     struct device *master;
0093 
0094     struct da9030_adc_res adc;
0095     struct delayed_work work;
0096     unsigned int interval;
0097 
0098     struct power_supply_info *battery_info;
0099 
0100     struct da9030_battery_thresholds thresholds;
0101 
0102     unsigned int charge_milliamp;
0103     unsigned int charge_millivolt;
0104 
0105     /* charger status */
0106     bool chdet;
0107     uint8_t fault;
0108     int mA;
0109     int mV;
0110     bool is_on;
0111 
0112     struct notifier_block nb;
0113 
0114     /* platform callbacks for battery low and critical events */
0115     void (*battery_low)(void);
0116     void (*battery_critical)(void);
0117 
0118     struct dentry *debug_file;
0119 };
0120 
0121 static inline int da9030_reg_to_mV(int reg)
0122 {
0123     return ((reg * 2650) >> 8) + 2650;
0124 }
0125 
0126 static inline int da9030_millivolt_to_reg(int mV)
0127 {
0128     return ((mV - 2650) << 8) / 2650;
0129 }
0130 
0131 static inline int da9030_reg_to_mA(int reg)
0132 {
0133     return ((reg * 24000) >> 8) / 15;
0134 }
0135 
0136 #ifdef CONFIG_DEBUG_FS
0137 static int bat_debug_show(struct seq_file *s, void *data)
0138 {
0139     struct da9030_charger *charger = s->private;
0140 
0141     seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
0142     if (charger->chdet) {
0143         seq_printf(s, "iset = %dmA, vset = %dmV\n",
0144                charger->mA, charger->mV);
0145     }
0146 
0147     seq_printf(s, "vbat_res = %d (%dmV)\n",
0148            charger->adc.vbat_res,
0149            da9030_reg_to_mV(charger->adc.vbat_res));
0150     seq_printf(s, "vbatmin_res = %d (%dmV)\n",
0151            charger->adc.vbatmin_res,
0152            da9030_reg_to_mV(charger->adc.vbatmin_res));
0153     seq_printf(s, "vbatmintxon = %d (%dmV)\n",
0154            charger->adc.vbatmintxon,
0155            da9030_reg_to_mV(charger->adc.vbatmintxon));
0156     seq_printf(s, "ichmax_res = %d (%dmA)\n",
0157            charger->adc.ichmax_res,
0158            da9030_reg_to_mV(charger->adc.ichmax_res));
0159     seq_printf(s, "ichmin_res = %d (%dmA)\n",
0160            charger->adc.ichmin_res,
0161            da9030_reg_to_mA(charger->adc.ichmin_res));
0162     seq_printf(s, "ichaverage_res = %d (%dmA)\n",
0163            charger->adc.ichaverage_res,
0164            da9030_reg_to_mA(charger->adc.ichaverage_res));
0165     seq_printf(s, "vchmax_res = %d (%dmV)\n",
0166            charger->adc.vchmax_res,
0167            da9030_reg_to_mA(charger->adc.vchmax_res));
0168     seq_printf(s, "vchmin_res = %d (%dmV)\n",
0169            charger->adc.vchmin_res,
0170            da9030_reg_to_mV(charger->adc.vchmin_res));
0171 
0172     return 0;
0173 }
0174 
0175 DEFINE_SHOW_ATTRIBUTE(bat_debug);
0176 
0177 static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
0178 {
0179     charger->debug_file = debugfs_create_file("charger", 0666, NULL,
0180                           charger, &bat_debug_fops);
0181     return charger->debug_file;
0182 }
0183 
0184 static void da9030_bat_remove_debugfs(struct da9030_charger *charger)
0185 {
0186     debugfs_remove(charger->debug_file);
0187 }
0188 #else
0189 static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
0190 {
0191     return NULL;
0192 }
0193 static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger)
0194 {
0195 }
0196 #endif
0197 
0198 static inline void da9030_read_adc(struct da9030_charger *charger,
0199                    struct da9030_adc_res *adc)
0200 {
0201     da903x_reads(charger->master, DA9030_VBAT_RES,
0202              sizeof(*adc), (uint8_t *)adc);
0203 }
0204 
0205 static void da9030_charger_update_state(struct da9030_charger *charger)
0206 {
0207     uint8_t val;
0208 
0209     da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val);
0210     charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0;
0211     charger->mA = ((val >> 3) & 0xf) * 100;
0212     charger->mV = (val & 0x7) * 50 + 4000;
0213 
0214     da9030_read_adc(charger, &charger->adc);
0215     da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault);
0216     charger->chdet = da903x_query_status(charger->master,
0217                              DA9030_STATUS_CHDET);
0218 }
0219 
0220 static void da9030_set_charge(struct da9030_charger *charger, int on)
0221 {
0222     uint8_t val;
0223 
0224     if (on) {
0225         val = DA9030_CHRG_CHARGER_ENABLE;
0226         val |= (charger->charge_milliamp / 100) << 3;
0227         val |= (charger->charge_millivolt - 4000) / 50;
0228         charger->is_on = 1;
0229     } else {
0230         val = 0;
0231         charger->is_on = 0;
0232     }
0233 
0234     da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
0235 
0236     power_supply_changed(charger->psy);
0237 }
0238 
0239 static void da9030_charger_check_state(struct da9030_charger *charger)
0240 {
0241     da9030_charger_update_state(charger);
0242 
0243     /* we wake or boot with external power on */
0244     if (!charger->is_on) {
0245         if ((charger->chdet) &&
0246             (charger->adc.vbat_res <
0247              charger->thresholds.vbat_charge_start)) {
0248             da9030_set_charge(charger, 1);
0249         }
0250     } else {
0251         /* Charger has been pulled out */
0252         if (!charger->chdet) {
0253             da9030_set_charge(charger, 0);
0254             return;
0255         }
0256 
0257         if (charger->adc.vbat_res >=
0258             charger->thresholds.vbat_charge_stop) {
0259             da9030_set_charge(charger, 0);
0260             da903x_write(charger->master, DA9030_VBATMON,
0261                        charger->thresholds.vbat_charge_restart);
0262         } else if (charger->adc.vbat_res >
0263                charger->thresholds.vbat_low) {
0264             /* we are charging and passed LOW_THRESH,
0265                so upate DA9030 VBAT threshold
0266              */
0267             da903x_write(charger->master, DA9030_VBATMON,
0268                      charger->thresholds.vbat_low);
0269         }
0270         if (charger->adc.vchmax_res > charger->thresholds.vcharge_max ||
0271             charger->adc.vchmin_res < charger->thresholds.vcharge_min ||
0272             /* Tempreture readings are negative */
0273             charger->adc.tbat_res < charger->thresholds.tbat_high ||
0274             charger->adc.tbat_res > charger->thresholds.tbat_low) {
0275             /* disable charger */
0276             da9030_set_charge(charger, 0);
0277         }
0278     }
0279 }
0280 
0281 static void da9030_charging_monitor(struct work_struct *work)
0282 {
0283     struct da9030_charger *charger;
0284 
0285     charger = container_of(work, struct da9030_charger, work.work);
0286 
0287     da9030_charger_check_state(charger);
0288 
0289     /* reschedule for the next time */
0290     schedule_delayed_work(&charger->work, charger->interval);
0291 }
0292 
0293 static enum power_supply_property da9030_battery_props[] = {
0294     POWER_SUPPLY_PROP_MODEL_NAME,
0295     POWER_SUPPLY_PROP_STATUS,
0296     POWER_SUPPLY_PROP_HEALTH,
0297     POWER_SUPPLY_PROP_TECHNOLOGY,
0298     POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
0299     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0300     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0301     POWER_SUPPLY_PROP_CURRENT_AVG,
0302 };
0303 
0304 static void da9030_battery_check_status(struct da9030_charger *charger,
0305                     union power_supply_propval *val)
0306 {
0307     if (charger->chdet) {
0308         if (charger->is_on)
0309             val->intval = POWER_SUPPLY_STATUS_CHARGING;
0310         else
0311             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0312     } else {
0313         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0314     }
0315 }
0316 
0317 static void da9030_battery_check_health(struct da9030_charger *charger,
0318                     union power_supply_propval *val)
0319 {
0320     if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP)
0321         val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
0322     else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER)
0323         val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0324     else
0325         val->intval = POWER_SUPPLY_HEALTH_GOOD;
0326 }
0327 
0328 static int da9030_battery_get_property(struct power_supply *psy,
0329                    enum power_supply_property psp,
0330                    union power_supply_propval *val)
0331 {
0332     struct da9030_charger *charger = power_supply_get_drvdata(psy);
0333 
0334     switch (psp) {
0335     case POWER_SUPPLY_PROP_STATUS:
0336         da9030_battery_check_status(charger, val);
0337         break;
0338     case POWER_SUPPLY_PROP_HEALTH:
0339         da9030_battery_check_health(charger, val);
0340         break;
0341     case POWER_SUPPLY_PROP_TECHNOLOGY:
0342         val->intval = charger->battery_info->technology;
0343         break;
0344     case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
0345         val->intval = charger->battery_info->voltage_max_design;
0346         break;
0347     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0348         val->intval = charger->battery_info->voltage_min_design;
0349         break;
0350     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0351         val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000;
0352         break;
0353     case POWER_SUPPLY_PROP_CURRENT_AVG:
0354         val->intval =
0355             da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000;
0356         break;
0357     case POWER_SUPPLY_PROP_MODEL_NAME:
0358         val->strval = charger->battery_info->name;
0359         break;
0360     default:
0361         break;
0362     }
0363 
0364     return 0;
0365 }
0366 
0367 static void da9030_battery_vbat_event(struct da9030_charger *charger)
0368 {
0369     da9030_read_adc(charger, &charger->adc);
0370 
0371     if (charger->is_on)
0372         return;
0373 
0374     if (charger->adc.vbat_res < charger->thresholds.vbat_low) {
0375         /* set VBAT threshold for critical */
0376         da903x_write(charger->master, DA9030_VBATMON,
0377                  charger->thresholds.vbat_crit);
0378         if (charger->battery_low)
0379             charger->battery_low();
0380     } else if (charger->adc.vbat_res <
0381            charger->thresholds.vbat_crit) {
0382         /* notify the system of battery critical */
0383         if (charger->battery_critical)
0384             charger->battery_critical();
0385     }
0386 }
0387 
0388 static int da9030_battery_event(struct notifier_block *nb, unsigned long event,
0389                 void *data)
0390 {
0391     struct da9030_charger *charger =
0392         container_of(nb, struct da9030_charger, nb);
0393 
0394     switch (event) {
0395     case DA9030_EVENT_CHDET:
0396         cancel_delayed_work_sync(&charger->work);
0397         schedule_work(&charger->work.work);
0398         break;
0399     case DA9030_EVENT_VBATMON:
0400         da9030_battery_vbat_event(charger);
0401         break;
0402     case DA9030_EVENT_CHIOVER:
0403     case DA9030_EVENT_TBAT:
0404         da9030_set_charge(charger, 0);
0405         break;
0406     }
0407 
0408     return 0;
0409 }
0410 
0411 static void da9030_battery_convert_thresholds(struct da9030_charger *charger,
0412                           struct da9030_battery_info *pdata)
0413 {
0414     charger->thresholds.tbat_low = pdata->tbat_low;
0415     charger->thresholds.tbat_high = pdata->tbat_high;
0416     charger->thresholds.tbat_restart  = pdata->tbat_restart;
0417 
0418     charger->thresholds.vbat_low =
0419         da9030_millivolt_to_reg(pdata->vbat_low);
0420     charger->thresholds.vbat_crit =
0421         da9030_millivolt_to_reg(pdata->vbat_crit);
0422     charger->thresholds.vbat_charge_start =
0423         da9030_millivolt_to_reg(pdata->vbat_charge_start);
0424     charger->thresholds.vbat_charge_stop =
0425         da9030_millivolt_to_reg(pdata->vbat_charge_stop);
0426     charger->thresholds.vbat_charge_restart =
0427         da9030_millivolt_to_reg(pdata->vbat_charge_restart);
0428 
0429     charger->thresholds.vcharge_min =
0430         da9030_millivolt_to_reg(pdata->vcharge_min);
0431     charger->thresholds.vcharge_max =
0432         da9030_millivolt_to_reg(pdata->vcharge_max);
0433 }
0434 
0435 static void da9030_battery_setup_psy(struct da9030_charger *charger)
0436 {
0437     struct power_supply_desc *psy_desc = &charger->psy_desc;
0438     struct power_supply_info *info = charger->battery_info;
0439 
0440     psy_desc->name = info->name;
0441     psy_desc->use_for_apm = info->use_for_apm;
0442     psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
0443     psy_desc->get_property = da9030_battery_get_property;
0444 
0445     psy_desc->properties = da9030_battery_props;
0446     psy_desc->num_properties = ARRAY_SIZE(da9030_battery_props);
0447 };
0448 
0449 static int da9030_battery_charger_init(struct da9030_charger *charger)
0450 {
0451     char v[5];
0452     int ret;
0453 
0454     v[0] = v[1] = charger->thresholds.vbat_low;
0455     v[2] = charger->thresholds.tbat_high;
0456     v[3] = charger->thresholds.tbat_restart;
0457     v[4] = charger->thresholds.tbat_low;
0458 
0459     ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v);
0460     if (ret)
0461         return ret;
0462 
0463     /*
0464      * Enable reference voltage supply for ADC from the LDO_INTERNAL
0465      * regulator. Must be set before ADC measurements can be made.
0466      */
0467     ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL,
0468                DA9030_ADC_LDO_INT_ENABLE |
0469                DA9030_ADC_TBATREF_ENABLE);
0470     if (ret)
0471         return ret;
0472 
0473     /* enable auto ADC measuremnts */
0474     return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL,
0475                 DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON |
0476                 DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE |
0477                 DA9030_ADC_VBAT_ENABLE |
0478                 DA9030_ADC_AUTO_SLEEP_ENABLE);
0479 }
0480 
0481 static int da9030_battery_probe(struct platform_device *pdev)
0482 {
0483     struct da9030_charger *charger;
0484     struct power_supply_config psy_cfg = {};
0485     struct da9030_battery_info *pdata = pdev->dev.platform_data;
0486     int ret;
0487 
0488     if (pdata == NULL)
0489         return -EINVAL;
0490 
0491     if (pdata->charge_milliamp >= 1500 ||
0492         pdata->charge_millivolt < 4000 ||
0493         pdata->charge_millivolt > 4350)
0494         return -EINVAL;
0495 
0496     charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
0497     if (charger == NULL)
0498         return -ENOMEM;
0499 
0500     charger->master = pdev->dev.parent;
0501 
0502     /* 10 seconds between monitor runs unless platform defines other
0503        interval */
0504     charger->interval = msecs_to_jiffies(
0505         (pdata->batmon_interval ? : 10) * 1000);
0506 
0507     charger->charge_milliamp = pdata->charge_milliamp;
0508     charger->charge_millivolt = pdata->charge_millivolt;
0509     charger->battery_info = pdata->battery_info;
0510     charger->battery_low = pdata->battery_low;
0511     charger->battery_critical = pdata->battery_critical;
0512 
0513     da9030_battery_convert_thresholds(charger, pdata);
0514 
0515     ret = da9030_battery_charger_init(charger);
0516     if (ret)
0517         goto err_charger_init;
0518 
0519     INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor);
0520     schedule_delayed_work(&charger->work, charger->interval);
0521 
0522     charger->nb.notifier_call = da9030_battery_event;
0523     ret = da903x_register_notifier(charger->master, &charger->nb,
0524                        DA9030_EVENT_CHDET |
0525                        DA9030_EVENT_VBATMON |
0526                        DA9030_EVENT_CHIOVER |
0527                        DA9030_EVENT_TBAT);
0528     if (ret)
0529         goto err_notifier;
0530 
0531     da9030_battery_setup_psy(charger);
0532     psy_cfg.drv_data = charger;
0533     charger->psy = power_supply_register(&pdev->dev, &charger->psy_desc,
0534                          &psy_cfg);
0535     if (IS_ERR(charger->psy)) {
0536         ret = PTR_ERR(charger->psy);
0537         goto err_ps_register;
0538     }
0539 
0540     charger->debug_file = da9030_bat_create_debugfs(charger);
0541     platform_set_drvdata(pdev, charger);
0542     return 0;
0543 
0544 err_ps_register:
0545     da903x_unregister_notifier(charger->master, &charger->nb,
0546                    DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
0547                    DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
0548 err_notifier:
0549     cancel_delayed_work(&charger->work);
0550 
0551 err_charger_init:
0552     return ret;
0553 }
0554 
0555 static int da9030_battery_remove(struct platform_device *dev)
0556 {
0557     struct da9030_charger *charger = platform_get_drvdata(dev);
0558 
0559     da9030_bat_remove_debugfs(charger);
0560 
0561     da903x_unregister_notifier(charger->master, &charger->nb,
0562                    DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
0563                    DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
0564     cancel_delayed_work_sync(&charger->work);
0565     da9030_set_charge(charger, 0);
0566     power_supply_unregister(charger->psy);
0567 
0568     return 0;
0569 }
0570 
0571 static struct platform_driver da903x_battery_driver = {
0572     .driver = {
0573         .name   = "da903x-battery",
0574     },
0575     .probe = da9030_battery_probe,
0576     .remove = da9030_battery_remove,
0577 };
0578 
0579 module_platform_driver(da903x_battery_driver);
0580 
0581 MODULE_DESCRIPTION("DA9030 battery charger driver");
0582 MODULE_AUTHOR("Mike Rapoport, CompuLab");
0583 MODULE_LICENSE("GPL");