static int __init twl6030_bci_battery_probe(struct platform_device *pdev) { struct twl6030_bci_platform_data *pdata = pdev->dev.platform_data; struct twl6030_bci_device_info *di; int irq; int ret; u8 rd_reg = 0, controller_stat = 0; di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); ret = -EINVAL; goto err_pdata; } di->dev = &pdev->dev; di->bat.name = "twl6030_bci_battery"; di->bat.supplied_to = twl6030_bci_supplied_to; di->bat.num_supplicants = ARRAY_SIZE(twl6030_bci_supplied_to); di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = twl6030_bci_battery_props; di->bat.num_properties = ARRAY_SIZE(twl6030_bci_battery_props); di->bat.get_property = twl6030_bci_battery_get_property; di->bat.external_power_changed = twl6030_bci_battery_external_power_changed; di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; di->bk_bat.name = "twl6030_bci_bk_battery"; di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bk_bat.properties = twl6030_bk_bci_battery_props; di->bk_bat.num_properties = ARRAY_SIZE(twl6030_bk_bci_battery_props); di->bk_bat.get_property = twl6030_bk_bci_battery_get_property; di->bk_bat.external_power_changed = NULL; /* * Android expects a battery type POWER_SUPPLY_TYPE_USB * as a usb charger battery. This battery * and its "online" property are used to determine if the * usb cable is plugged in or not. */ di->usb_bat.name = "twl6030_bci_usb_battery"; di->usb_bat.supplied_to = twl6030_bci_supplied_to; di->usb_bat.type = POWER_SUPPLY_TYPE_USB; di->usb_bat.properties = twl6030_usb_battery_props; di->usb_bat.num_properties = ARRAY_SIZE(twl6030_usb_battery_props); di->usb_bat.get_property = twl6030_usb_battery_get_property; di->usb_bat.external_power_changed = NULL; di->vac_priority = 1; platform_set_drvdata(pdev, di); /* settings for temperature sensing */ ret = twl6030battery_temp_setup(); if (ret) goto temp_setup_fail; /* request charger fault interruption */ irq = platform_get_irq(pdev, 1); ret = request_irq(irq, twl6030charger_fault_interrupt, 0, "twl_bci_fault", di); if (ret) { dev_dbg(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto batt_irq_fail; } /* request charger ctrl interruption */ irq = platform_get_irq(pdev, 0); ret = request_irq(irq, twl6030charger_ctrl_interrupt, 0, "twl_bci_ctrl", di); if (ret) { dev_dbg(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto chg_irq_fail; } twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_STS_C); ret = power_supply_register(&pdev->dev, &di->bat); if (ret) { dev_dbg(&pdev->dev, "failed to register main battery\n"); goto batt_failed; } INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_bci_monitor_work, twl6030_bci_battery_work); schedule_delayed_work(&di->twl6030_bci_monitor_work, 0); ret = power_supply_register(&pdev->dev, &di->bk_bat); if (ret) { dev_dbg(&pdev->dev, "failed to register backup battery\n"); goto bk_batt_failed; } ret = power_supply_register(&pdev->dev, &di->usb_bat); if (ret) { dev_dbg(&pdev->dev, "failed to register usb source\n"); goto usb_batt_failed; } INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_bk_bci_monitor_work, twl6030_bk_bci_battery_work); schedule_delayed_work(&di->twl6030_bk_bci_monitor_work, 500); twl_i2c_read_u8(TWL6030_MODULE_ID0, &rd_reg, REG_MISC1); rd_reg = rd_reg | VAC_MEAS | VBAT_MEAS | BB_MEAS; twl_i2c_write_u8(TWL6030_MODULE_ID0, rd_reg, REG_MISC1); twl_i2c_read_u8(TWL6030_MODULE_ID1, &rd_reg, REG_TOGGLE1); rd_reg = rd_reg | ENABLE_FUELGUAGE; twl_i2c_write_u8(TWL6030_MODULE_ID1, rd_reg, REG_TOGGLE1); twl_i2c_read_u8(TWL_MODULE_MADC, &rd_reg, TWL6030_GPADC_CTRL); rd_reg = rd_reg | ENABLE_ISOURCE; twl_i2c_write_u8(TWL_MODULE_MADC, rd_reg, TWL6030_GPADC_CTRL); twl_i2c_read_u8(TWL_MODULE_USB, &rd_reg, REG_USB_VBUS_CTRL_SET); rd_reg = rd_reg | VBUS_MEAS; twl_i2c_write_u8(TWL_MODULE_USB, rd_reg, REG_USB_VBUS_CTRL_SET); twl_i2c_read_u8(TWL_MODULE_USB, &rd_reg, REG_USB_ID_CTRL_SET); rd_reg = rd_reg | ID_MEAS; twl_i2c_write_u8(TWL_MODULE_USB, rd_reg, REG_USB_ID_CTRL_SET); /* initialize for USB charging */ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MBAT_TEMP, CONTROLLER_INT_MASK); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MASK_MCHARGERUSB_THMREG, CHARGERUSB_INT_MASK); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_VOREG_4P2, CHARGERUSB_VOREG); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_VICHRG_1500, CHARGERUSB_VICHRG); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CTRL2_VITERM_100, CHARGERUSB_CTRL2); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CIN_LIMIT_NONE, CHARGERUSB_CINLIMIT); twl_i2c_write_u8(TWL6030_MODULE_CHARGER, CHARGERUSB_CTRLLIMIT2_1500, CHARGERUSB_CTRLLIMIT2); twl_i2c_write_u8(TWL6030_MODULE_BQ, 0xa0, REG_SAFETY_LIMIT); twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &controller_stat, CONTROLLER_STAT1); if (controller_stat & VBUS_DET) twl6030_start_usb_charger(); if (controller_stat & VAC_DET) twl6030_start_ac_charger(); return 0; usb_batt_failed: power_supply_unregister(&di->bk_bat); bk_batt_failed: power_supply_unregister(&di->bat); batt_failed: free_irq(irq, di); chg_irq_fail: irq = platform_get_irq(pdev, 1); free_irq(irq, NULL); err_pdata: batt_irq_fail: temp_setup_fail: kfree(di); return ret; }
static int __devinit twl6030_bci_battery_probe(struct platform_device *pdev) { struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; struct twl6030_bci_device_info *di; int irq = -1; int ret; int i; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); return -EINVAL; } di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; di->platform_data = kmemdup(pdata, sizeof(*pdata), GFP_KERNEL); if (!di->platform_data) { kfree(di); return -ENOMEM; } di->state = STATE_BATTERY; di->monitoring_interval = 15; di->capacity_max_uAh = 570000; di->full_jiffies = msecs_to_jiffies(120 * 1000) + jiffies; di->vbat_jiffies = jiffies; di->dev = &pdev->dev; di->bat.name = "twl6030_battery"; di->bat.supplied_to = twl6030_bci_supplied_to; di->bat.num_supplicants = ARRAY_SIZE(twl6030_bci_supplied_to); di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = twl6030_bci_battery_props; di->bat.num_properties = ARRAY_SIZE(twl6030_bci_battery_props); di->bat.get_property = twl6030_bci_battery_get_property; di->bat_health = POWER_SUPPLY_HEALTH_GOOD; di->usb.name = "twl6030_usb"; di->usb.type = POWER_SUPPLY_TYPE_USB; di->usb.properties = twl6030_usb_props; di->usb.num_properties = ARRAY_SIZE(twl6030_usb_props); di->usb.get_property = twl6030_usb_get_property; platform_set_drvdata(pdev, di); wake_lock_init(&usb_wake_lock, WAKE_LOCK_SUSPEND, "usb_wake_lock"); wake_lock_init(&battery_wake_lock, WAKE_LOCK_SUSPEND, "battery_wake_lock"); di->wq = create_freezable_workqueue(dev_name(&pdev->dev)); /* settings for temperature sensing */ ret = twl6030battery_temp_setup(true); if (ret) goto temp_setup_fail; ret = power_supply_register(&pdev->dev, &di->bat); if (ret) { dev_err(&pdev->dev, "failed to register main battery\n"); goto batt_failed; } ret = power_supply_register(&pdev->dev, &di->usb); if (ret) { dev_err(&pdev->dev, "failed to register usb power supply\n"); goto usb_failed; } di->charge_n1 = 0; di->timer_n1 = 0; INIT_WORK(&di->charge_control_work, twl6030_charge_control_work); INIT_WORK(&di->charge_fault_work, twl6030_charge_fault_work); INIT_WORK(&di->calibration_work, twl6030_calibration_work); INIT_DELAYED_WORK_DEFERRABLE(&di->monitor_work, twl6030_monitor_work); ret = twl6030battery_voltage_setup(di); if (ret) dev_err(&pdev->dev, "voltage measurement setup failed\n"); ret = twl6030battery_current_setup(true); if (ret) dev_err(&pdev->dev, "current measurement setup failed\n"); /* initialize for USB charging */ twl6030_config_limit1_reg(di, pdata->max_charger_voltagemV); twl6030_config_limit2_reg(di, pdata->max_charger_currentmA); ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MBAT_TEMP, CONTROLLER_INT_MASK); if (ret) goto init_failed; ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER, MASK_MCHARGERUSB_THMREG | MASK_MCURRENT_TERM, CHARGERUSB_INT_MASK); if (ret) goto init_failed; di->charger_outcurrentmA = di->platform_data->max_charger_currentmA; twl6030_set_watchdog(di, 32); di->nb.notifier_call = twl6030_usb_notifier_call; di->otg = otg_get_transceiver(); if (di->otg) { ret = otg_register_notifier(di->otg, &di->nb); if (ret) dev_err(&pdev->dev, "otg register notifier failed %d\n", ret); } else dev_err(&pdev->dev, "otg_get_transceiver failed %d\n", ret); di->charger_incurrentmA = twl6030_get_usb_max_power(di->otg); di->gpadc_vbat_chnl = TWL6030_GPADC_VBAT_CHNL; di->voltage_mV = twl6030_get_gpadc_conversion(di, di->gpadc_vbat_chnl); dev_info(&pdev->dev, "Battery Voltage at Bootup is %d mV\n", di->voltage_mV); /* initialize the voltage history table */ /* TODO: consider the best initial values for the table */ for (i=0; i < VOLTAGE_HISTORY_LENGTH; i++) di->voltage_history[i] = di->voltage_mV; /* start with a rough estimate */ di->capacity = twl6030_estimate_capacity(di); if (di->capacity < 5) di->capacity = 5; if (di->capacity > 50) di->capacity = 50; ret = twl6030backupbatt_setup(); if (ret) dev_err(&pdev->dev, "Backup Bat charging setup failed\n"); /* request charger fault interruption */ irq = platform_get_irq(pdev, 1); ret = request_threaded_irq(irq, NULL, twl6030charger_fault_interrupt, 0, "twl_bci_fault", di); if (ret) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto init_failed; } /* request charger ctrl interruption */ irq = platform_get_irq(pdev, 0); ret = request_threaded_irq(irq, NULL, twl6030charger_ctrl_interrupt, 0, "twl_bci_ctrl", di); if (ret) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", irq, ret); goto chg_irq_fail; } twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_FAULT_INT_MASK, REG_INT_MSK_STS_C); ret = sysfs_create_group(&pdev->dev.kobj, &twl6030_bci_attr_group); if (ret) dev_err(&pdev->dev, "could not create sysfs files\n"); queue_work(di->wq, &di->calibration_work); queue_delayed_work(di->wq, &di->monitor_work, 0); return 0; /* TODO: fix fail exit mess */ chg_irq_fail: irq = platform_get_irq(pdev, 1); free_irq(irq, di); init_failed: power_supply_unregister(&di->usb); usb_failed: power_supply_unregister(&di->bat); batt_failed: if (irq != -1) free_irq(irq, di); temp_setup_fail: wake_lock_destroy(&usb_wake_lock); platform_set_drvdata(pdev, NULL); kfree(di); return ret; }