예제 #1
0
static ssize_t p3_bat_store(struct device *dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{
	int x = 0;
	int ret = 0;
	const ptrdiff_t off = attr - p3_battery_attrs;

	switch (off) {
	case FORCE_USB_CHARGING:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x == 1)
				test_batterydata->info.force_usb_charging = true;
			else
				test_batterydata->info.force_usb_charging = false;
			ret = count;
			p3_bat_status_update(&test_batterydata->psy_battery);
		}
		break;
	case BATT_RESET_SOC:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x == 1) {
				if (!check_ta_conn(test_batterydata))
					fg_reset_soc();
			}
			ret = count;
		}
		p3_bat_status_update(&test_batterydata->psy_battery);
		pr_debug("Reset SOC:%d ", x);
		break;
	case BATT_RESET_CAP:
		if (sscanf(buf, "%d\n", &x) == 1 ||
			x == 2 || x == 3 || x == 4) {
			if (x == 1 || x == 2 || x == 3 || x == 4)
				fg_reset_capacity();
			ret = count;
		}
		pr_debug("%s: Reset CAP:%d\n", __func__, x);
		break;
	case BATT_FG_REG:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x == 1)
				fg_periodic_read();
			ret = count;
		}
		pr_debug("%s: FG Register:%d\n", __func__, x);
		break;
#ifdef CONFIG_SAMSUNG_LPM_MODE
	case CHARGING_MODE_BOOTING:
		if (sscanf(buf, "%d\n", &x) == 1) {
			test_batterydata->charging_mode_booting = x;
			ret = count;
		}
		break;
#endif
	default:
		ret = -EINVAL;
	}
	return ret;
}
static void p3_bat_work(struct work_struct *work)
{
	struct battery_data *battery =
		container_of(work, struct battery_data, battery_work);
	unsigned long flags;

	pr_debug("bat work ");
	p3_bat_status_update(&battery->psy_battery);
	battery->last_poll = alarm_get_elapsed_realtime();

	/* prevent suspend before starting the alarm */
	local_irq_save(flags);
	wake_unlock(&battery->work_wake_lock);
	p3_program_alarm(battery, FAST_POLL);
	local_irq_restore(flags);
}
static int __devinit p3_bat_probe(struct platform_device *pdev)
{
	struct p3_battery_platform_data *pdata = dev_get_platdata(&pdev->dev);
	struct battery_data *battery;
	int ret;
	unsigned long trigger;
	int irq_num;

	battery = kzalloc(sizeof(*battery), GFP_KERNEL);
	if (!battery)
		return -ENOMEM;

	battery->pdata = pdata;
	if (!battery->pdata) {
		pr_err("%s : No platform data\n", __func__);
		return -EINVAL;
	}

	battery->pdata->init_charger_gpio();

	platform_set_drvdata(pdev, battery);
	test_batterydata = battery;

	battery->present = 1;
	battery->info.level = 100;
	battery->info.charging_source = CHARGER_BATTERY;
	battery->info.batt_health = POWER_SUPPLY_HEALTH_GOOD;
	battery->is_first_check = true;

	battery->psy_battery.name = "battery";
	battery->psy_battery.type = POWER_SUPPLY_TYPE_BATTERY;
	battery->psy_battery.properties = p3_battery_properties;
	battery->psy_battery.num_properties = ARRAY_SIZE(p3_battery_properties);
	battery->psy_battery.get_property = p3_bat_get_property;

	battery->psy_usb.name = "usb";
	battery->psy_usb.type = POWER_SUPPLY_TYPE_USB;
	battery->psy_usb.supplied_to = supply_list;
	battery->psy_usb.num_supplicants = ARRAY_SIZE(supply_list);
	battery->psy_usb.properties = p3_power_properties;
	battery->psy_usb.num_properties = ARRAY_SIZE(p3_power_properties);
	battery->psy_usb.get_property = p3_usb_get_property;

	battery->psy_ac.name = "ac";
	battery->psy_ac.type = POWER_SUPPLY_TYPE_MAINS;
	battery->psy_ac.supplied_to = supply_list;
	battery->psy_ac.num_supplicants = ARRAY_SIZE(supply_list);
	battery->psy_ac.properties = p3_power_properties;
	battery->psy_ac.num_properties = ARRAY_SIZE(p3_power_properties);
	battery->psy_ac.get_property = p3_ac_get_property;

	mutex_init(&battery->work_lock);

	wake_lock_init(&battery->vbus_wake_lock, WAKE_LOCK_SUSPEND,
		"vbus wake lock");
	wake_lock_init(&battery->work_wake_lock, WAKE_LOCK_SUSPEND,
		"batt_work wake lock");
	wake_lock_init(&battery->cable_wake_lock, WAKE_LOCK_SUSPEND,
		"temp wake lock");
	wake_lock_init(&battery->fullcharge_wake_lock, WAKE_LOCK_SUSPEND,
		"fullcharge wake lock");
#ifdef __TEST_DEVICE_DRIVER__
	wake_lock_init(&battery->wake_lock_for_dev, WAKE_LOCK_SUSPEND,
		"test mode wake lock");
#endif /* __TEST_DEVICE_DRIVER__ */

	INIT_WORK(&battery->battery_work, p3_bat_work);
	INIT_WORK(&battery->cable_work, p3_cable_work);
	INIT_DELAYED_WORK(&battery->fuelgauge_work, fuelgauge_work_handler);
	INIT_DELAYED_WORK(&battery->fullcharging_work,
			fullcharging_work_handler);
	INIT_DELAYED_WORK(&battery->full_comp_work, full_comp_work_handler);
	INIT_DELAYED_WORK(&battery->TA_work, p3_TA_work_handler);
	battery->p3_TA_workqueue = create_singlethread_workqueue(
		"p3_TA_workqueue");
	if (!battery->p3_TA_workqueue) {
		pr_err("Failed to create single workqueue\n");
		ret = -ENOMEM;
		goto err_workqueue_init;
	}

	battery->last_poll = alarm_get_elapsed_realtime();
	alarm_init(&battery->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
		p3_battery_alarm);

	ret = power_supply_register(&pdev->dev, &battery->psy_battery);
	if (ret) {
		pr_err("Failed to register battery power supply.\n");
		goto err_battery_psy_register;
	}

	ret = power_supply_register(&pdev->dev, &battery->psy_usb);
	if (ret) {
		pr_err("Failed to register USB power supply.\n");
		goto err_usb_psy_register;
	}

	ret = power_supply_register(&pdev->dev, &battery->psy_ac);
	if (ret) {
		pr_err("Failed to register AC power supply.\n");
		goto err_ac_psy_register;
	}

	/* create sec detail attributes */
	p3_bat_create_attrs(battery->psy_battery.dev);

#ifdef __TEST_DEVICE_DRIVER__
	sec_batt_test_create_attrs(battery->psy_ac.dev);
#endif /* __TEST_DEVICE_DRIVER__ */

	battery->p3_battery_initial = 1;
	battery->low_batt_boot_flag = 0;

	battery->connect_irq = gpio_to_irq(pdata->charger.connect_line);
	if (check_ta_conn(battery))
		trigger = IRQF_TRIGGER_HIGH;
	else
		trigger = IRQF_TRIGGER_LOW;

	if (request_irq(battery->connect_irq, p3_TA_interrupt_handler, trigger,
			"TA_CON intr", battery)) {
		pr_err("p3_TA_interrupt_handler register failed!\n");
		goto err_charger_irq;
	}
	disable_irq(battery->connect_irq);

	// Get initial cable status and enable connection irq.
	p3_get_cable_status(battery);
	battery->previous_cable_status = battery->current_cable_status;
	enable_irq(battery->connect_irq);

	if (check_ta_conn(battery) && check_UV_charging_case())
		battery->low_batt_boot_flag = 1;

	mutex_lock(&battery->work_lock);
	fg_alert_init();
	mutex_unlock(&battery->work_lock);

	p3_bat_status_update(&battery->psy_battery);

	p3_cable_check_status(battery);

	/* before enable fullcharge interrupt, check fullcharge */
	if (battery->info.charging_source == CHARGER_AC
		&& battery->info.charging_enabled
		&& gpio_get_value(pdata->charger.fullcharge_line) == 1)
		p3_cable_charging(battery);

	/* Request IRQ */
	irq_num = gpio_to_irq(max17042_chip_data->pdata->fuel_alert_line);
	if (request_irq(irq_num, low_battery_isr,
			IRQF_TRIGGER_FALLING, "FUEL_ALRT irq", battery))
		pr_err("Can NOT request irq 'IRQ_FUEL_ALERT' %d ", irq_num);

#ifdef CONFIG_SAMSUNG_LPM_MODE
	lpm_mode_check(battery);
#endif

	return 0;

err_charger_irq:
	alarm_cancel(&battery->alarm);
	power_supply_unregister(&battery->psy_ac);
err_ac_psy_register:
	power_supply_unregister(&battery->psy_usb);
err_usb_psy_register:
	power_supply_unregister(&battery->psy_battery);
err_battery_psy_register:
	destroy_workqueue(battery->p3_TA_workqueue);
err_workqueue_init:
	wake_lock_destroy(&battery->vbus_wake_lock);
	wake_lock_destroy(&battery->work_wake_lock);
	wake_lock_destroy(&battery->cable_wake_lock);
	wake_lock_destroy(&battery->fullcharge_wake_lock);
	mutex_destroy(&battery->work_lock);
	kfree(battery);

	return ret;
}