Exemple #1
0
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;
}
Exemple #2
0
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;
}