0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/init.h>
0016 #include <linux/types.h>
0017 #include <linux/device.h>
0018 #include <linux/sysfs.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/power_supply.h>
0021
0022 #include <linux/mfd/pcf50633/core.h>
0023 #include <linux/mfd/pcf50633/mbc.h>
0024
0025 struct pcf50633_mbc {
0026 struct pcf50633 *pcf;
0027
0028 int adapter_online;
0029 int usb_online;
0030
0031 struct power_supply *usb;
0032 struct power_supply *adapter;
0033 struct power_supply *ac;
0034 };
0035
0036 int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
0037 {
0038 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
0039 int ret = 0;
0040 u8 bits;
0041 u8 mbcs2, chgmod;
0042 unsigned int mbcc5;
0043
0044 if (ma >= 1000) {
0045 bits = PCF50633_MBCC7_USB_1000mA;
0046 ma = 1000;
0047 } else if (ma >= 500) {
0048 bits = PCF50633_MBCC7_USB_500mA;
0049 ma = 500;
0050 } else if (ma >= 100) {
0051 bits = PCF50633_MBCC7_USB_100mA;
0052 ma = 100;
0053 } else {
0054 bits = PCF50633_MBCC7_USB_SUSPEND;
0055 ma = 0;
0056 }
0057
0058 ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
0059 PCF50633_MBCC7_USB_MASK, bits);
0060 if (ret)
0061 dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
0062 else
0063 dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 if (mbc->pcf->pdata->charger_reference_current_ma) {
0077 mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
0078 if (mbcc5 > 255)
0079 mbcc5 = 255;
0080 pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
0081 }
0082
0083 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
0084 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
0085
0086
0087
0088
0089
0090 if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
0091 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
0092 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
0093 else {
0094 pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
0095 PCF50633_MBCC1_CHGENA);
0096 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
0097 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
0098 }
0099
0100 power_supply_changed(mbc->usb);
0101
0102 return ret;
0103 }
0104 EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set);
0105
0106 int pcf50633_mbc_get_status(struct pcf50633 *pcf)
0107 {
0108 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
0109 int status = 0;
0110 u8 chgmod;
0111
0112 if (!mbc)
0113 return 0;
0114
0115 chgmod = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2)
0116 & PCF50633_MBCS2_MBC_MASK;
0117
0118 if (mbc->usb_online)
0119 status |= PCF50633_MBC_USB_ONLINE;
0120 if (chgmod == PCF50633_MBCS2_MBC_USB_PRE ||
0121 chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT ||
0122 chgmod == PCF50633_MBCS2_MBC_USB_FAST ||
0123 chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT)
0124 status |= PCF50633_MBC_USB_ACTIVE;
0125 if (mbc->adapter_online)
0126 status |= PCF50633_MBC_ADAPTER_ONLINE;
0127 if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE ||
0128 chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT ||
0129 chgmod == PCF50633_MBCS2_MBC_ADP_FAST ||
0130 chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT)
0131 status |= PCF50633_MBC_ADAPTER_ACTIVE;
0132
0133 return status;
0134 }
0135 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status);
0136
0137 int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf)
0138 {
0139 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
0140
0141 if (!mbc)
0142 return 0;
0143
0144 return mbc->usb_online;
0145 }
0146 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status);
0147
0148 static ssize_t
0149 show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
0150 {
0151 struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0152
0153 u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
0154 u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
0155
0156 return sprintf(buf, "%d\n", chgmod);
0157 }
0158 static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
0159
0160 static ssize_t
0161 show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
0162 {
0163 struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0164 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0165 PCF50633_MBCC7_USB_MASK;
0166 unsigned int ma;
0167
0168 if (usblim == PCF50633_MBCC7_USB_1000mA)
0169 ma = 1000;
0170 else if (usblim == PCF50633_MBCC7_USB_500mA)
0171 ma = 500;
0172 else if (usblim == PCF50633_MBCC7_USB_100mA)
0173 ma = 100;
0174 else
0175 ma = 0;
0176
0177 return sprintf(buf, "%u\n", ma);
0178 }
0179
0180 static ssize_t set_usblim(struct device *dev,
0181 struct device_attribute *attr, const char *buf, size_t count)
0182 {
0183 struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0184 unsigned long ma;
0185 int ret;
0186
0187 ret = kstrtoul(buf, 10, &ma);
0188 if (ret)
0189 return ret;
0190
0191 pcf50633_mbc_usb_curlim_set(mbc->pcf, ma);
0192
0193 return count;
0194 }
0195
0196 static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
0197
0198 static ssize_t
0199 show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
0200 {
0201 struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0202 u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
0203 unsigned int ma;
0204
0205 if (!mbc->pcf->pdata->charger_reference_current_ma)
0206 return -ENODEV;
0207
0208 ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8;
0209
0210 return sprintf(buf, "%u\n", ma);
0211 }
0212
0213 static ssize_t set_chglim(struct device *dev,
0214 struct device_attribute *attr, const char *buf, size_t count)
0215 {
0216 struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
0217 unsigned long ma;
0218 unsigned int mbcc5;
0219 int ret;
0220
0221 if (!mbc->pcf->pdata->charger_reference_current_ma)
0222 return -ENODEV;
0223
0224 ret = kstrtoul(buf, 10, &ma);
0225 if (ret)
0226 return ret;
0227
0228 mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
0229 if (mbcc5 > 255)
0230 mbcc5 = 255;
0231 pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
0232
0233 return count;
0234 }
0235
0236
0237
0238
0239
0240
0241 static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
0242
0243 static struct attribute *pcf50633_mbc_sysfs_attrs[] = {
0244 &dev_attr_chgmode.attr,
0245 &dev_attr_usb_curlim.attr,
0246 &dev_attr_chg_curlim.attr,
0247 NULL,
0248 };
0249
0250 ATTRIBUTE_GROUPS(pcf50633_mbc_sysfs);
0251
0252 static void
0253 pcf50633_mbc_irq_handler(int irq, void *data)
0254 {
0255 struct pcf50633_mbc *mbc = data;
0256
0257
0258 if (irq == PCF50633_IRQ_USBINS) {
0259 mbc->usb_online = 1;
0260 } else if (irq == PCF50633_IRQ_USBREM) {
0261 mbc->usb_online = 0;
0262 pcf50633_mbc_usb_curlim_set(mbc->pcf, 0);
0263 }
0264
0265
0266 if (irq == PCF50633_IRQ_ADPINS)
0267 mbc->adapter_online = 1;
0268 else if (irq == PCF50633_IRQ_ADPREM)
0269 mbc->adapter_online = 0;
0270
0271 power_supply_changed(mbc->ac);
0272 power_supply_changed(mbc->usb);
0273 power_supply_changed(mbc->adapter);
0274
0275 if (mbc->pcf->pdata->mbc_event_callback)
0276 mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
0277 }
0278
0279 static int adapter_get_property(struct power_supply *psy,
0280 enum power_supply_property psp,
0281 union power_supply_propval *val)
0282 {
0283 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0284 int ret = 0;
0285
0286 switch (psp) {
0287 case POWER_SUPPLY_PROP_ONLINE:
0288 val->intval = mbc->adapter_online;
0289 break;
0290 default:
0291 ret = -EINVAL;
0292 break;
0293 }
0294 return ret;
0295 }
0296
0297 static int usb_get_property(struct power_supply *psy,
0298 enum power_supply_property psp,
0299 union power_supply_propval *val)
0300 {
0301 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0302 int ret = 0;
0303 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0304 PCF50633_MBCC7_USB_MASK;
0305
0306 switch (psp) {
0307 case POWER_SUPPLY_PROP_ONLINE:
0308 val->intval = mbc->usb_online &&
0309 (usblim <= PCF50633_MBCC7_USB_500mA);
0310 break;
0311 default:
0312 ret = -EINVAL;
0313 break;
0314 }
0315 return ret;
0316 }
0317
0318 static int ac_get_property(struct power_supply *psy,
0319 enum power_supply_property psp,
0320 union power_supply_propval *val)
0321 {
0322 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy);
0323 int ret = 0;
0324 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
0325 PCF50633_MBCC7_USB_MASK;
0326
0327 switch (psp) {
0328 case POWER_SUPPLY_PROP_ONLINE:
0329 val->intval = mbc->usb_online &&
0330 (usblim == PCF50633_MBCC7_USB_1000mA);
0331 break;
0332 default:
0333 ret = -EINVAL;
0334 break;
0335 }
0336 return ret;
0337 }
0338
0339 static enum power_supply_property power_props[] = {
0340 POWER_SUPPLY_PROP_ONLINE,
0341 };
0342
0343 static const u8 mbc_irq_handlers[] = {
0344 PCF50633_IRQ_ADPINS,
0345 PCF50633_IRQ_ADPREM,
0346 PCF50633_IRQ_USBINS,
0347 PCF50633_IRQ_USBREM,
0348 PCF50633_IRQ_BATFULL,
0349 PCF50633_IRQ_CHGHALT,
0350 PCF50633_IRQ_THLIMON,
0351 PCF50633_IRQ_THLIMOFF,
0352 PCF50633_IRQ_USBLIMON,
0353 PCF50633_IRQ_USBLIMOFF,
0354 PCF50633_IRQ_LOWSYS,
0355 PCF50633_IRQ_LOWBAT,
0356 };
0357
0358 static const struct power_supply_desc pcf50633_mbc_adapter_desc = {
0359 .name = "adapter",
0360 .type = POWER_SUPPLY_TYPE_MAINS,
0361 .properties = power_props,
0362 .num_properties = ARRAY_SIZE(power_props),
0363 .get_property = &adapter_get_property,
0364 };
0365
0366 static const struct power_supply_desc pcf50633_mbc_usb_desc = {
0367 .name = "usb",
0368 .type = POWER_SUPPLY_TYPE_USB,
0369 .properties = power_props,
0370 .num_properties = ARRAY_SIZE(power_props),
0371 .get_property = usb_get_property,
0372 };
0373
0374 static const struct power_supply_desc pcf50633_mbc_ac_desc = {
0375 .name = "ac",
0376 .type = POWER_SUPPLY_TYPE_MAINS,
0377 .properties = power_props,
0378 .num_properties = ARRAY_SIZE(power_props),
0379 .get_property = ac_get_property,
0380 };
0381
0382 static int pcf50633_mbc_probe(struct platform_device *pdev)
0383 {
0384 struct power_supply_config psy_cfg = {};
0385 struct power_supply_config usb_psy_cfg;
0386 struct pcf50633_mbc *mbc;
0387 int i;
0388 u8 mbcs1;
0389
0390 mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL);
0391 if (!mbc)
0392 return -ENOMEM;
0393
0394 platform_set_drvdata(pdev, mbc);
0395 mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
0396
0397
0398 for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
0399 pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
0400 pcf50633_mbc_irq_handler, mbc);
0401
0402 psy_cfg.supplied_to = mbc->pcf->pdata->batteries;
0403 psy_cfg.num_supplicants = mbc->pcf->pdata->num_batteries;
0404 psy_cfg.drv_data = mbc;
0405
0406
0407 mbc->adapter = power_supply_register(&pdev->dev,
0408 &pcf50633_mbc_adapter_desc,
0409 &psy_cfg);
0410 if (IS_ERR(mbc->adapter)) {
0411 dev_err(mbc->pcf->dev, "failed to register adapter\n");
0412 return PTR_ERR(mbc->adapter);
0413 }
0414
0415 usb_psy_cfg = psy_cfg;
0416 usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups;
0417
0418 mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc,
0419 &usb_psy_cfg);
0420 if (IS_ERR(mbc->usb)) {
0421 dev_err(mbc->pcf->dev, "failed to register usb\n");
0422 power_supply_unregister(mbc->adapter);
0423 return PTR_ERR(mbc->usb);
0424 }
0425
0426 mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc,
0427 &psy_cfg);
0428 if (IS_ERR(mbc->ac)) {
0429 dev_err(mbc->pcf->dev, "failed to register ac\n");
0430 power_supply_unregister(mbc->adapter);
0431 power_supply_unregister(mbc->usb);
0432 return PTR_ERR(mbc->ac);
0433 }
0434
0435 mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
0436 if (mbcs1 & PCF50633_MBCS1_USBPRES)
0437 pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
0438 if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
0439 pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);
0440
0441 return 0;
0442 }
0443
0444 static int pcf50633_mbc_remove(struct platform_device *pdev)
0445 {
0446 struct pcf50633_mbc *mbc = platform_get_drvdata(pdev);
0447 int i;
0448
0449
0450 for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
0451 pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
0452
0453 power_supply_unregister(mbc->usb);
0454 power_supply_unregister(mbc->adapter);
0455 power_supply_unregister(mbc->ac);
0456
0457 return 0;
0458 }
0459
0460 static struct platform_driver pcf50633_mbc_driver = {
0461 .driver = {
0462 .name = "pcf50633-mbc",
0463 },
0464 .probe = pcf50633_mbc_probe,
0465 .remove = pcf50633_mbc_remove,
0466 };
0467
0468 module_platform_driver(pcf50633_mbc_driver);
0469
0470 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
0471 MODULE_DESCRIPTION("PCF50633 mbc driver");
0472 MODULE_LICENSE("GPL");
0473 MODULE_ALIAS("platform:pcf50633-mbc");