android wake_lock 在底层实现系统不休眠

说明:

1、三星方案

2、具体实现,添加一下三行代码:

定义:

static struct wake_lock wake_lock_always;
初始化:

wake_lock_init(&wake_lock_always, WAKE_LOCK_SUSPEND, "wake_lock_always");
加锁:

wake_lock(&wake_lock_always); 



/*
 * linux/drivers/power/samsung_fake_battery.c
 *
 * Battery measurement code for samsung smdk platform.
 *
 * Copyright (C) 2011 Samsung Electronics.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/irq.h>
#include <linux/wakelock.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <plat/gpio-cfg.h>

#define FAKE_BAT_LEVEL	80

static struct wake_lock vbus_wake_lock;
static struct wake_lock wake_lock_always;

/* Prototypes */
static ssize_t samsung_fake_bat_show_property(struct device *dev,
				struct device_attribute *attr,
				char *buf);
static ssize_t samsung_fake_bat_store_property(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count);

static struct device *dev;
static int samsung_fake_battery_initial;

static char *status_text[] = {
	[POWER_SUPPLY_STATUS_UNKNOWN] =		"Unknown",
	[POWER_SUPPLY_STATUS_CHARGING] =	"Charging",
	[POWER_SUPPLY_STATUS_DISCHARGING] =	"Discharging",
	[POWER_SUPPLY_STATUS_NOT_CHARGING] =	"Not Charging",
	[POWER_SUPPLY_STATUS_FULL] =		"Full",
};

typedef enum {
	CHARGER_BATTERY = 0,
	CHARGER_USB,
	CHARGER_AC,
	CHARGER_DISCHARGE
} charger_type_t;

struct battery_info {
	u32 batt_id;		/* Battery ID from ADC */
	u32 batt_vol;		/* Battery voltage from ADC */
	u32 batt_vol_adc;	/* Battery ADC value */
	u32 batt_vol_adc_cal;	/* Battery ADC value (calibrated)*/
	u32 batt_temp;		/* Battery Temperature (C) from ADC */
	u32 batt_temp_adc;	/* Battery Temperature ADC value */
	u32 batt_temp_adc_cal;	/* Battery Temperature ADC value (calibrated) */
	u32 batt_current;	/* Battery current from ADC */
	u32 level;		/* formula */
	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
	u32 charging_enabled;	/* 0: Disable, 1: Enable */
	u32 batt_health;	/* Battery Health (Authority) */
	u32 batt_is_full;	/* 0 : Not full 1: Full */
};

/* lock to protect the battery info */
static DEFINE_MUTEX(work_lock);

struct samsung_fake_battery_info {
	int present;
	int polling;
	unsigned long polling_interval;

	struct battery_info bat_info;
};
static struct samsung_fake_battery_info samsung_fake_bat_info;

static int samsung_get_bat_level(struct power_supply *bat_ps)
{
	return FAKE_BAT_LEVEL;
}

static int samsung_get_bat_vol(struct power_supply *bat_ps)
{
	int bat_vol = 0;

	return bat_vol;
}

static u32 samsung_get_bat_health(void)
{
	return samsung_fake_bat_info.bat_info.batt_health;
}

static int samsung_get_bat_temp(struct power_supply *bat_ps)
{
	int temp = 0;

	return temp;
}

static int samsung_fake_bat_get_charging_status(void)
{
	charger_type_t charger = CHARGER_BATTERY;
	int ret = 0;

	charger = samsung_fake_bat_info.bat_info.charging_source;

	switch (charger) {
	case CHARGER_BATTERY:
		ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
		break;
	case CHARGER_USB:
	case CHARGER_AC:
		if (samsung_fake_bat_info.bat_info.level == 100 &&
		    samsung_fake_bat_info.bat_info.batt_is_full)
			ret = POWER_SUPPLY_STATUS_FULL;
		else
			ret = POWER_SUPPLY_STATUS_CHARGING;
		break;
	case CHARGER_DISCHARGE:
		ret = POWER_SUPPLY_STATUS_DISCHARGING;
		break;
	default:
		ret = POWER_SUPPLY_STATUS_UNKNOWN;
	}
	dev_dbg(dev, "%s : %s\n", __func__, status_text[ret]);

	return ret;
}

static int samsung_fake_bat_get_property(struct power_supply *bat_ps,
					 enum power_supply_property psp,
					 union power_supply_propval *val)
{
	dev_dbg(bat_ps->dev, "%s : psp = %d\n", __func__, psp);

	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		val->intval = samsung_fake_bat_get_charging_status();
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = samsung_get_bat_health();
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = samsung_fake_bat_info.present;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		val->intval = samsung_fake_bat_info.bat_info.level;
		dev_dbg(dev, "%s : level = %d\n", __func__,
				val->intval);
		break;
	case POWER_SUPPLY_PROP_TEMP:
		val->intval = samsung_fake_bat_info.bat_info.batt_temp;
		dev_dbg(bat_ps->dev, "%s : temp = %d\n", __func__,
				val->intval);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int samsung_power_get_property(struct power_supply *bat_ps,
				enum power_supply_property psp,
				union power_supply_propval *val)
{
	charger_type_t charger;

	dev_dbg(bat_ps->dev, "%s : psp = %d\n", __func__, psp);

	charger = samsung_fake_bat_info.bat_info.charging_source;

	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		if (bat_ps->type == POWER_SUPPLY_TYPE_MAINS)
			val->intval = (charger == CHARGER_AC ? 1 : 0);
		else if (bat_ps->type == POWER_SUPPLY_TYPE_USB)
			val->intval = (charger == CHARGER_USB ? 1 : 0);
		else
			val->intval = 0;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

#define SAMSUNG_FAKE_BAT_ATTR(_name)			\
{							\
	.attr = { .name = #_name,},			\
	.show = samsung_fake_bat_show_property,		\
	.store = samsung_fake_bat_store_property,	\
}

static struct device_attribute samsung_fake_battery_attrs[] = {
	SAMSUNG_FAKE_BAT_ATTR(batt_vol),
	SAMSUNG_FAKE_BAT_ATTR(batt_vol_adc),
	SAMSUNG_FAKE_BAT_ATTR(batt_vol_adc_cal),
	SAMSUNG_FAKE_BAT_ATTR(batt_temp),
	SAMSUNG_FAKE_BAT_ATTR(batt_temp_adc),
	SAMSUNG_FAKE_BAT_ATTR(batt_temp_adc_cal),
};

enum {
	BATT_VOL = 0,
	BATT_VOL_ADC,
	BATT_VOL_ADC_CAL,
	BATT_TEMP,
	BATT_TEMP_ADC,
	BATT_TEMP_ADC_CAL,
};

static int samsung_fake_bat_create_attrs(struct device * dev)
{
	int i, rc;

	for (i = 0; i < ARRAY_SIZE(samsung_fake_battery_attrs); i++) {
		rc = device_create_file(dev, &samsung_fake_battery_attrs[i]);
		if (rc)
		goto attrs_failed;
	}
	goto succeed;

attrs_failed:
	while (i--)
	device_remove_file(dev, &samsung_fake_battery_attrs[i]);
succeed:
	return rc;
}

static ssize_t samsung_fake_bat_show_property(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	int i = 0;
	const ptrdiff_t off = attr - samsung_fake_battery_attrs;

	switch (off) {
	case BATT_VOL:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_vol);
	break;
	case BATT_VOL_ADC:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_vol_adc);
		break;
	case BATT_VOL_ADC_CAL:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_vol_adc_cal);
		break;
	case BATT_TEMP:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_temp);
		break;
	case BATT_TEMP_ADC:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_temp_adc);
		break;
	case BATT_TEMP_ADC_CAL:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
			samsung_fake_bat_info.bat_info.batt_temp_adc_cal);
		break;
	default:
		i = -EINVAL;
	}

	return i;
}

static ssize_t samsung_fake_bat_store_property(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	int x = 0;
	int ret = 0;
	const ptrdiff_t off = attr - samsung_fake_battery_attrs;

	switch (off) {
	case BATT_VOL_ADC_CAL:
		if (sscanf(buf, "%d\n", &x) == 1) {
			samsung_fake_bat_info.bat_info.batt_vol_adc_cal = x;
			ret = count;
		}
		dev_info(dev, "%s : batt_vol_adc_cal = %d\n", __func__, x);
		break;
	case BATT_TEMP_ADC_CAL:
		if (sscanf(buf, "%d\n", &x) == 1) {
			samsung_fake_bat_info.bat_info.batt_temp_adc_cal = x;
			ret = count;
		}
		dev_info(dev, "%s : batt_temp_adc_cal = %d\n", __func__, x);
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
}

static enum power_supply_property samsung_fake_battery_properties[] = {
	POWER_SUPPLY_PROP_STATUS,
	POWER_SUPPLY_PROP_HEALTH,
	POWER_SUPPLY_PROP_PRESENT,
	POWER_SUPPLY_PROP_TECHNOLOGY,
	POWER_SUPPLY_PROP_CAPACITY,
};

static enum power_supply_property samsung_power_properties[] = {
	POWER_SUPPLY_PROP_ONLINE,
};

static char *supply_list[] = {
	"battery",
};

static struct power_supply samsung_power_supplies[] = {
	{
		.name = "battery",
		.type = POWER_SUPPLY_TYPE_BATTERY,
		.properties = samsung_fake_battery_properties,
		.num_properties = ARRAY_SIZE(samsung_fake_battery_properties),
		.get_property = samsung_fake_bat_get_property,
	}, {
		.name = "usb",
		.type = POWER_SUPPLY_TYPE_USB,
		.supplied_to = supply_list,
		.num_supplicants = ARRAY_SIZE(supply_list),
		.properties = samsung_power_properties,
		.num_properties = ARRAY_SIZE(samsung_power_properties),
		.get_property = samsung_power_get_property,
	}, {
		.name = "ac",
		.type = POWER_SUPPLY_TYPE_MAINS,
		.supplied_to = supply_list,
		.num_supplicants = ARRAY_SIZE(supply_list),
		.properties = samsung_power_properties,
		.num_properties = ARRAY_SIZE(samsung_power_properties),
		.get_property = samsung_power_get_property,
	},
};

static int samsung_cable_status_update(int status)
{
	int ret = 0;
	charger_type_t source = CHARGER_BATTERY;

	dev_dbg(dev, "%s\n", __func__);

	if (!samsung_fake_battery_initial)
		return -EPERM;

	switch (status) {
	case CHARGER_BATTERY:
		dev_dbg(dev, "%s : cable NOT PRESENT\n", __func__);
		samsung_fake_bat_info.bat_info.charging_source = CHARGER_BATTERY;
		break;
	case CHARGER_USB:
		dev_dbg(dev, "%s : cable USB\n", __func__);
		samsung_fake_bat_info.bat_info.charging_source = CHARGER_USB;
		break;
	case CHARGER_AC:
		dev_dbg(dev, "%s : cable AC\n", __func__);
		samsung_fake_bat_info.bat_info.charging_source = CHARGER_AC;
		break;
	case CHARGER_DISCHARGE:
		dev_dbg(dev, "%s : Discharge\n", __func__);
		samsung_fake_bat_info.bat_info.charging_source = CHARGER_DISCHARGE;
		break;
	default:
		dev_err(dev, "%s : Nat supported status\n", __func__);
		ret = -EINVAL;
	}
	source = samsung_fake_bat_info.bat_info.charging_source;

	if (source == CHARGER_USB || source == CHARGER_AC)
		wake_lock(&vbus_wake_lock);
	else
		wake_lock_timeout(&vbus_wake_lock, HZ / 2);

	/* if the power source changes, all power supplies may change state */
	power_supply_changed(&samsung_power_supplies[CHARGER_BATTERY]);

	dev_dbg(dev, "%s : call power_supply_changed\n", __func__);
	return ret;
}

static void samsung_fake_bat_status_update(struct power_supply *bat_ps)
{
	int old_level, old_temp, old_is_full;
	dev_dbg(dev, "%s ++\n", __func__);

	if (!samsung_fake_battery_initial)
		return;

	mutex_lock(&work_lock);

	old_temp = samsung_fake_bat_info.bat_info.batt_temp;
	old_level = samsung_fake_bat_info.bat_info.level;
	old_is_full = samsung_fake_bat_info.bat_info.batt_is_full;
	samsung_fake_bat_info.bat_info.batt_temp = samsung_get_bat_temp(bat_ps);
	samsung_fake_bat_info.bat_info.level = samsung_get_bat_level(bat_ps);
	samsung_fake_bat_info.bat_info.batt_vol = samsung_get_bat_vol(bat_ps);

	if (old_level != samsung_fake_bat_info.bat_info.level ||
	    old_temp != samsung_fake_bat_info.bat_info.batt_temp ||
	    old_is_full != samsung_fake_bat_info.bat_info.batt_is_full) {
		power_supply_changed(bat_ps);
		dev_dbg(dev, "%s : call power_supply_changed\n", __func__);
	}

	mutex_unlock(&work_lock);
	dev_dbg(dev, "%s --\n", __func__);
}

void samsung_cable_check_status(int flag)
{
    charger_type_t status = 0;

    if (flag == 0)
	status = CHARGER_BATTERY;
    else
	status = CHARGER_USB;

    samsung_cable_status_update(status);
}
EXPORT_SYMBOL(samsung_cable_check_status);

#ifdef CONFIG_PM
static int samsung_fake_bat_suspend(struct device *dev)
{
	return 0;
}

static void samsung_fake_bat_resume(struct device *dev)
{
}
#else
#define samsung_fake_bat_suspend NULL
#define samsung_fake_bat_resume NULL
#endif /* CONFIG_PM */

static int __devinit samsung_fake_bat_probe(struct platform_device *pdev)
{
	int i;
	int ret = 0;

	dev = &pdev->dev;
	dev_info(dev, "%s\n", __func__);

	samsung_fake_bat_info.present = 1;

	samsung_fake_bat_info.bat_info.batt_id = 0;
	samsung_fake_bat_info.bat_info.batt_vol = 0;
	samsung_fake_bat_info.bat_info.batt_vol_adc = 0;
	samsung_fake_bat_info.bat_info.batt_vol_adc_cal = 0;
	samsung_fake_bat_info.bat_info.batt_temp = 0;
	samsung_fake_bat_info.bat_info.batt_temp_adc = 0;
	samsung_fake_bat_info.bat_info.batt_temp_adc_cal = 0;
	samsung_fake_bat_info.bat_info.batt_current = 0;
	samsung_fake_bat_info.bat_info.level = 0;
	samsung_fake_bat_info.bat_info.charging_source = CHARGER_BATTERY;
	samsung_fake_bat_info.bat_info.charging_enabled = 0;
	samsung_fake_bat_info.bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD;

	/* init power supplier framework */
	for (i = 0; i < ARRAY_SIZE(samsung_power_supplies); i++) {
		ret = power_supply_register(&pdev->dev,
				&samsung_power_supplies[i]);
		if (ret) {
			dev_err(dev, "Failed to register"
					"power supply %d,%d\n", i, ret);
			goto __end__;
		}
	}

	/* create sec detail attributes */
	samsung_fake_bat_create_attrs(samsung_power_supplies[CHARGER_BATTERY].dev);

	samsung_fake_battery_initial = 1;

	samsung_fake_bat_status_update(
			&samsung_power_supplies[CHARGER_BATTERY]);
	wake_lock(&wake_lock_always);   //mid-icon do not need suspend

__end__:
	return ret;
}

static int __devexit samsung_fake_bat_remove(struct platform_device *pdev)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(samsung_power_supplies); i++)
		power_supply_unregister(&samsung_power_supplies[i]);

	return 0;
}

static const struct dev_pm_ops samsung_fake_bat_pm_ops = {
	.prepare	= samsung_fake_bat_suspend,
	.complete	= samsung_fake_bat_resume,
};

static struct platform_driver samsung_fake_bat_driver = {
	.driver = {
		.name	= "samsung-fake-battery",
		.owner	= THIS_MODULE,
		.pm	= &samsung_fake_bat_pm_ops,
	},
	.probe		= samsung_fake_bat_probe,
	.remove		= __devexit_p(samsung_fake_bat_remove),
};

static int __init samsung_fake_bat_init(void)
{
	wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
	wake_lock_init(&wake_lock_always, WAKE_LOCK_SUSPEND, "wake_lock_always");

	return platform_driver_register(&samsung_fake_bat_driver);
}

static void __exit samsung_fake_bat_exit(void)
{
	platform_driver_unregister(&samsung_fake_bat_driver);
}

module_init(samsung_fake_bat_init);
module_exit(samsung_fake_bat_exit);

MODULE_AUTHOR("HuiSung Kang <hs1218.kang@samsung.com>");
MODULE_DESCRIPTION("SAMSUNG Fake battery driver for SMDK Board");
MODULE_LICENSE("GPL");


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值