Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Backup battery driver for Wolfson Microelectronics wm831x PMICs
0004  *
0005  * Copyright 2009 Wolfson Microelectronics PLC.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/err.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/power_supply.h>
0012 #include <linux/slab.h>
0013 
0014 #include <linux/mfd/wm831x/core.h>
0015 #include <linux/mfd/wm831x/auxadc.h>
0016 #include <linux/mfd/wm831x/pmu.h>
0017 #include <linux/mfd/wm831x/pdata.h>
0018 
0019 struct wm831x_backup {
0020     struct wm831x *wm831x;
0021     struct power_supply *backup;
0022     struct power_supply_desc backup_desc;
0023     char name[20];
0024 };
0025 
0026 static int wm831x_backup_read_voltage(struct wm831x *wm831x,
0027                      enum wm831x_auxadc src,
0028                      union power_supply_propval *val)
0029 {
0030     int ret;
0031 
0032     ret = wm831x_auxadc_read_uv(wm831x, src);
0033     if (ret >= 0)
0034         val->intval = ret;
0035 
0036     return ret;
0037 }
0038 
0039 /*********************************************************************
0040  *      Backup supply properties
0041  *********************************************************************/
0042 
0043 static void wm831x_config_backup(struct wm831x *wm831x)
0044 {
0045     struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
0046     struct wm831x_backup_pdata *pdata;
0047     int ret, reg;
0048 
0049     if (!wm831x_pdata || !wm831x_pdata->backup) {
0050         dev_warn(wm831x->dev,
0051              "No backup battery charger configuration\n");
0052         return;
0053     }
0054 
0055     pdata = wm831x_pdata->backup;
0056 
0057     reg = 0;
0058 
0059     if (pdata->charger_enable)
0060         reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA;
0061     if (pdata->no_constant_voltage)
0062         reg |= WM831X_BKUP_CHG_MODE;
0063 
0064     switch (pdata->vlim) {
0065     case 2500:
0066         break;
0067     case 3100:
0068         reg |= WM831X_BKUP_CHG_VLIM;
0069         break;
0070     default:
0071         dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n",
0072             pdata->vlim);
0073     }
0074 
0075     switch (pdata->ilim) {
0076     case 100:
0077         break;
0078     case 200:
0079         reg |= 1;
0080         break;
0081     case 300:
0082         reg |= 2;
0083         break;
0084     case 400:
0085         reg |= 3;
0086         break;
0087     default:
0088         dev_err(wm831x->dev, "Invalid backup current limit %duA\n",
0089             pdata->ilim);
0090     }
0091 
0092     ret = wm831x_reg_unlock(wm831x);
0093     if (ret != 0) {
0094         dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
0095         return;
0096     }
0097 
0098     ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL,
0099                   WM831X_BKUP_CHG_ENA_MASK |
0100                   WM831X_BKUP_CHG_MODE_MASK |
0101                   WM831X_BKUP_BATT_DET_ENA_MASK |
0102                   WM831X_BKUP_CHG_VLIM_MASK |
0103                   WM831X_BKUP_CHG_ILIM_MASK,
0104                   reg);
0105     if (ret != 0)
0106         dev_err(wm831x->dev,
0107             "Failed to set backup charger config: %d\n", ret);
0108 
0109     wm831x_reg_lock(wm831x);
0110 }
0111 
0112 static int wm831x_backup_get_prop(struct power_supply *psy,
0113                   enum power_supply_property psp,
0114                   union power_supply_propval *val)
0115 {
0116     struct wm831x_backup *devdata = dev_get_drvdata(psy->dev.parent);
0117     struct wm831x *wm831x = devdata->wm831x;
0118     int ret = 0;
0119 
0120     ret = wm831x_reg_read(wm831x, WM831X_BACKUP_CHARGER_CONTROL);
0121     if (ret < 0)
0122         return ret;
0123 
0124     switch (psp) {
0125     case POWER_SUPPLY_PROP_STATUS:
0126         if (ret & WM831X_BKUP_CHG_STS)
0127             val->intval = POWER_SUPPLY_STATUS_CHARGING;
0128         else
0129             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0130         break;
0131 
0132     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0133         ret = wm831x_backup_read_voltage(wm831x, WM831X_AUX_BKUP_BATT,
0134                         val);
0135         break;
0136 
0137     case POWER_SUPPLY_PROP_PRESENT:
0138         if (ret & WM831X_BKUP_CHG_STS)
0139             val->intval = 1;
0140         else
0141             val->intval = 0;
0142         break;
0143 
0144     default:
0145         ret = -EINVAL;
0146         break;
0147     }
0148 
0149     return ret;
0150 }
0151 
0152 static enum power_supply_property wm831x_backup_props[] = {
0153     POWER_SUPPLY_PROP_STATUS,
0154     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0155     POWER_SUPPLY_PROP_PRESENT,
0156 };
0157 
0158 /*********************************************************************
0159  *      Initialisation
0160  *********************************************************************/
0161 
0162 static int wm831x_backup_probe(struct platform_device *pdev)
0163 {
0164     struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
0165     struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
0166     struct wm831x_backup *devdata;
0167 
0168     devdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_backup),
0169                 GFP_KERNEL);
0170     if (devdata == NULL)
0171         return -ENOMEM;
0172 
0173     devdata->wm831x = wm831x;
0174     platform_set_drvdata(pdev, devdata);
0175 
0176     /* We ignore configuration failures since we can still read
0177      * back the status without enabling the charger (which may
0178      * already be enabled anyway).
0179      */
0180     wm831x_config_backup(wm831x);
0181 
0182     if (wm831x_pdata && wm831x_pdata->wm831x_num)
0183         snprintf(devdata->name, sizeof(devdata->name),
0184              "wm831x-backup.%d", wm831x_pdata->wm831x_num);
0185     else
0186         snprintf(devdata->name, sizeof(devdata->name),
0187              "wm831x-backup");
0188 
0189     devdata->backup_desc.name = devdata->name;
0190     devdata->backup_desc.type = POWER_SUPPLY_TYPE_BATTERY;
0191     devdata->backup_desc.properties = wm831x_backup_props;
0192     devdata->backup_desc.num_properties = ARRAY_SIZE(wm831x_backup_props);
0193     devdata->backup_desc.get_property = wm831x_backup_get_prop;
0194     devdata->backup = power_supply_register(&pdev->dev,
0195                         &devdata->backup_desc, NULL);
0196 
0197     return PTR_ERR_OR_ZERO(devdata->backup);
0198 }
0199 
0200 static int wm831x_backup_remove(struct platform_device *pdev)
0201 {
0202     struct wm831x_backup *devdata = platform_get_drvdata(pdev);
0203 
0204     power_supply_unregister(devdata->backup);
0205 
0206     return 0;
0207 }
0208 
0209 static struct platform_driver wm831x_backup_driver = {
0210     .probe = wm831x_backup_probe,
0211     .remove = wm831x_backup_remove,
0212     .driver = {
0213         .name = "wm831x-backup",
0214     },
0215 };
0216 
0217 module_platform_driver(wm831x_backup_driver);
0218 
0219 MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs");
0220 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0221 MODULE_LICENSE("GPL");
0222 MODULE_ALIAS("platform:wm831x-backup");