static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; pr_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery", chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, chg->psy_bat.properties = max8998_battery_props, chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props), chg->psy_bat.get_property = s3c_bat_get_property, chg->psy_bat.property_is_writeable = s3c_bat_property_is_writeable, chg->psy_bat.set_property = s3c_bat_set_property, chg->psy_usb.name = "usb", chg->psy_usb.type = POWER_SUPPLY_TYPE_USB, chg->psy_usb.supplied_to = supply_list, chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_usb.properties = s3c_power_properties, chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_usb.get_property = s3c_usb_get_property, chg->psy_ac.name = "ac", chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, chg->psy_ac.supplied_to = supply_list, chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_ac.properties = s3c_power_properties, chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_ac.get_property = s3c_ac_get_property, chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->bat_info.batt_temp = 100; //fake chg->bat_info.batt_percentage = 50; //fake, modem will bootup soon and update it... hopefully chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_update_reg(i2c, MAX8998_REG_CHGR1, /* disable */ (0x3 << MAX8998_SHIFT_RSTR), MAX8998_MASK_RSTR); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 6 Hr */ (0x2 << MAX8998_SHIFT_FT), MAX8998_MASK_FT); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 4.2V */ (0x0 << MAX8998_SHIFT_BATTSL), MAX8998_MASK_BATTSL); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 105c */ (0x0 << MAX8998_SHIFT_TMP), MAX8998_MASK_TMP); if (ret < 0) goto err_kfree; pr_info("%s : pmic interrupt registered\n", __func__); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_MASK_DCINR | MAX8998_MASK_DCINF)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_CHGRSTF_MASK); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, 0xFF); if (ret < 0) goto err_kfree; wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); INIT_WORK(&chg->bat_work, s3c_bat_work); chg->monitor_wqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_wake_lock; } chg->last_poll = alarm_get_elapsed_realtime(); alarm_init(&chg->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, s3c_battery_alarm); check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("Failed to register power supply psy_bat\n"); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("Failed to register power supply psy_usb\n"); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("Failed to register power supply psy_ac\n"); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("Failed to enable pmic irq wake\n"); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); alarm_cancel(&chg->alarm); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }
static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; bat_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery"; chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY; chg->psy_bat.properties = max8998_battery_props; chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props); chg->psy_bat.get_property = s3c_bat_get_property; chg->psy_usb.name = "usb"; chg->psy_usb.type = POWER_SUPPLY_TYPE_USB; chg->psy_usb.supplied_to = supply_list; chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list); chg->psy_usb.properties = s3c_power_properties; chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties); chg->psy_usb.get_property = s3c_usb_get_property; chg->psy_ac.name = "ac"; chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS; chg->psy_ac.supplied_to = supply_list; chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list); chg->psy_ac.properties = s3c_power_properties; chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties); chg->psy_ac.get_property = s3c_ac_get_property; chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->set_batt_full = false; chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; chg->esafe = MAX8998_USB_VBUS_AP_ON; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_IRQ_DCINR_MASK | MAX8998_IRQ_DCINF_MASK)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; #ifdef TOPOFF_CURRENT_CHECK ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, 0xFF); #else ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_TOPOFFR_MASK); #endif if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, ~(MAX8998_IRQ_LOBAT2_MASK | MAX8998_IRQ_LOBAT1_MASK)); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_ONOFF3, (1 << MAX8998_SHIFT_ENBATTMON), MAX8998_MASK_ENBATTMON); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG1, 0x7, 0x37); //3.57V if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG2, 0x5, 0x37); //3.4V if (ret < 0) goto err_kfree; max8998_lowbat_config(chg, 0); wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); wake_lock_init(&chg->lowbat_wake_lock, WAKE_LOCK_SUSPEND, "max8998-lowbat"); INIT_WORK(&chg->bat_work, s3c_bat_work); setup_timer(&chg->bat_work_timer, s3c_bat_work_timer_func, (unsigned long)chg); chg->monitor_wqueue = create_freezeable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("%s : Failed to create freezeable workqueue\n", __func__); ret = -ENOMEM; goto err_wake_lock; } check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("%s : Failed to register power supply psy_bat\n", __func__); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("%s : Failed to register power supply psy_usb\n", __func__); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("%s : Failed to register power supply psy_ac\n", __func__); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("%s : Failed to enable pmic irq wake\n", __func__); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; chg->callbacks.set_esafe = max8998_set_esafe; chg->callbacks.get_vdcin = max8998_get_vdcin; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); wake_lock_destroy(&chg->lowbat_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }