765 lines
21 KiB
C
765 lines
21 KiB
C
#include <linux/platform_device.h>
|
|
#include <linux/power_supply.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/string.h>
|
|
#include <linux/module.h> // 模块相关
|
|
#include <linux/slab.h>
|
|
#include <linux/kobject.h>
|
|
|
|
struct virtual_battery_data {
|
|
struct power_supply *psy;
|
|
int voltage_now;
|
|
int current_now;
|
|
int capacity;
|
|
int energy_full_design;
|
|
int energy_full;
|
|
int energy_now;
|
|
int status;
|
|
int temperature;
|
|
int online;
|
|
int power_now;
|
|
int charge_counter;
|
|
};
|
|
|
|
struct virtual_adapter_data {
|
|
struct power_supply *psy;
|
|
int online;
|
|
int type;
|
|
};
|
|
|
|
// 主数据结构,包含两个子结构
|
|
struct virtual_main_data {
|
|
struct virtual_battery_data battery_data;
|
|
struct virtual_adapter_data adapter_data;
|
|
};
|
|
|
|
static enum power_supply_property virtual_battery_props[] = {
|
|
POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW,
|
|
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL, POWER_SUPPLY_PROP_ENERGY_NOW,
|
|
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_TEMP,
|
|
POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_POWER_NOW,
|
|
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
|
};
|
|
|
|
static enum power_supply_property virtual_adapter_props[] = {
|
|
POWER_SUPPLY_PROP_ONLINE,
|
|
POWER_SUPPLY_PROP_TYPE, // 类型为AC
|
|
};
|
|
|
|
//static struct power_supply *virtual_battery;
|
|
//static struct kobject *battery_kobj;
|
|
|
|
// Sysfs 属性操作
|
|
//static ssize_t charge_counter_show(struct kobject *kobj,
|
|
// struct kobj_attribute *attr, char *buf)
|
|
/*
|
|
static ssize_t charge_counter_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
return sprintf(buf, "%d\n", data->charge_counter);
|
|
}
|
|
|
|
static ssize_t charge_counter_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->charge_counter);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->charge_counter = clamp_val(data->charge_counter, 0, 24000000);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t voltage_now_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
return sprintf(buf, "%d\n", data->voltage_now);
|
|
}
|
|
|
|
static ssize_t voltage_now_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->voltage_now);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->voltage_now = clamp_val(data->voltage_now, 0, 24000000);
|
|
data->power_now = (data->current_now * data->voltage_now)/1000000;
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t energy_now_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
return sprintf(buf, "%d\n", data->energy_now);
|
|
}
|
|
|
|
static ssize_t energy_now_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->energy_now);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->energy_now = clamp_val(data->energy_now, 0, 2000000000);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t energy_full_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
return sprintf(buf, "%d\n", data->energy_full);
|
|
}
|
|
|
|
static ssize_t energy_full_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->energy_full);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->energy_full = clamp_val(data->energy_full, 0, 2000000000);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t energy_full_design_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
return sprintf(buf, "%d\n", data->energy_full_design);
|
|
}
|
|
#if 0
|
|
static ssize_t energy_full_design_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_data *data = power_supply_get_drvdata(psy);
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->energy_full_design);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->energy_full_design =
|
|
clamp_val(data->energy_full_design, 0, 2000000000);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(data);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static ssize_t current_now_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
return sprintf(buf, "%d\n", data->current_now);
|
|
}
|
|
|
|
static ssize_t current_now_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->current_now);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->current_now = clamp_val(data->current_now, 0, 3000000);
|
|
data->power_now = (data->current_now * data->voltage_now)/1000000;
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t capacity_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
return sprintf(buf, "%d\n", data->capacity);
|
|
}
|
|
|
|
static ssize_t capacity_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->capacity);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->capacity = clamp_val(data->capacity, 0, 100);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t power_now_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
return sprintf(buf, "%d\n", data->power_now);
|
|
}
|
|
static ssize_t power_now_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_data *data = power_supply_get_drvdata(psy);
|
|
|
|
int ret;
|
|
ret = kstrtouint(buf, 10, &data->power_now);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
// 限制范围 0-100
|
|
data->capacity = clamp_val(data->power_now, 0, 20000000);
|
|
|
|
// 通知电源子系统更新
|
|
power_supply_changed(data);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t status_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
const char *status_str;
|
|
switch (data->status) {
|
|
case POWER_SUPPLY_STATUS_CHARGING:
|
|
status_str = "Charging";
|
|
break;
|
|
case POWER_SUPPLY_STATUS_DISCHARGING:
|
|
status_str = "Discharging";
|
|
break;
|
|
case POWER_SUPPLY_STATUS_FULL:
|
|
status_str = "Full";
|
|
break;
|
|
case POWER_SUPPLY_STATUS_NOT_CHARGING:
|
|
status_str = "Not Charging";
|
|
break;
|
|
default:
|
|
status_str = "Unknown";
|
|
}
|
|
return sprintf(buf, "%s\n", status_str);
|
|
}
|
|
|
|
static ssize_t status_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
if (sysfs_streq(buf, "Charging")) {
|
|
data->status = POWER_SUPPLY_STATUS_CHARGING;
|
|
} else if (sysfs_streq(buf, "Discharging")) {
|
|
data->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
|
} else if (sysfs_streq(buf, "Full")) {
|
|
data->status = POWER_SUPPLY_STATUS_FULL;
|
|
} else if (sysfs_streq(buf, "Not Charging")) {
|
|
data->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
|
|
power_supply_changed(psy);
|
|
return count;
|
|
}
|
|
*/
|
|
// 定义 sysfs 属性
|
|
/*
|
|
static struct kobj_attribute capacity_attr =
|
|
__ATTR(capacity, 0664, capacity_show, capacity_store);
|
|
static struct kobj_attribute status_attr =
|
|
__ATTR(status, 0664, status_show, status_store);
|
|
static struct kobj_attribute current_attr =
|
|
__ATTR(current_now, 0664, current_show, current_store);
|
|
static struct kobj_attribute energy_full_design_attr =
|
|
__ATTR(energy_full_design, 0664, energy_full_design_show,
|
|
energy_full_design_store);
|
|
static struct kobj_attribute energy_full_attr =
|
|
__ATTR(energy_full, 0664, energy_full_show, energy_full_store);
|
|
static struct kobj_attribute energy_attr =
|
|
__ATTR(energy_now, 0664, energy_show, energy_store);
|
|
static struct kobj_attribute voltage_attr =
|
|
__ATTR(voltage, 0664, voltage_show, voltage_store);
|
|
static struct kobj_attribute charge_counter_attr =
|
|
__ATTR(charge_counter, 0664, charge_counter_show, charge_counter_store);
|
|
|
|
static struct attribute *battery_attrs[] = {
|
|
&capacity_attr.attr,
|
|
&status_attr.attr,
|
|
¤t_attr.attr,
|
|
&energy_full_design_attr.attr,
|
|
&energy_full_attr.attr,
|
|
&energy_attr.attr,
|
|
&voltage_attr.attr,
|
|
&charge_counter_attr.attr,
|
|
NULL,
|
|
};
|
|
|
|
|
|
|
|
static struct attribute_group battery_attr_group = {
|
|
.attrs = battery_attrs,
|
|
};
|
|
|
|
|
|
|
|
static DEVICE_ATTR_RW(capacity);
|
|
static DEVICE_ATTR_RW(status);
|
|
static DEVICE_ATTR_RW(current_now);
|
|
static DEVICE_ATTR_RW(voltage_now);
|
|
static DEVICE_ATTR_RO(energy_full_design);
|
|
static DEVICE_ATTR_RW(energy_full);
|
|
static DEVICE_ATTR_RW(energy_now);
|
|
static DEVICE_ATTR_RW(charge_counter);
|
|
static DEVICE_ATTR_RO(power_now);
|
|
|
|
|
|
static struct attribute *virtual_battery_attrs[] = {
|
|
&dev_attr_capacity.attr,
|
|
&dev_attr_status.attr,
|
|
&dev_attr_current_now.attr,
|
|
&dev_attr_voltage_now.attr,
|
|
&dev_attr_energy_full_design.attr,
|
|
&dev_attr_energy_full.attr,
|
|
&dev_attr_energy_now.attr,
|
|
&dev_attr_charge_counter.attr,
|
|
&dev_attr_power_now.attr,
|
|
NULL,
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(virtual_battery);
|
|
|
|
// 导出到用户空间的sysfs接口
|
|
static ssize_t online_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
|
|
int online;
|
|
|
|
if (kstrtoint(buf, 10, &online))
|
|
return -EINVAL;
|
|
|
|
data->online = !!online;
|
|
power_supply_changed(psy);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t online_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct power_supply *psy = dev_get_drvdata(dev);
|
|
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
|
|
|
|
return sprintf(buf, "%d\n", data->online);
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(online);
|
|
|
|
static struct attribute *virtual_adapter_attrs[] = {
|
|
&dev_attr_online.attr,
|
|
NULL,
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(virtual_adapter);
|
|
*/
|
|
static int virtual_battery_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
|
val->intval = data->voltage_now;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
|
if (data->status == POWER_SUPPLY_STATUS_CHARGING)
|
|
val->intval = data->current_now;
|
|
else {
|
|
val->intval = -(data->current_now);
|
|
}
|
|
break;
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
val->intval = data->capacity;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
|
val->intval = data->energy_full_design;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ENERGY_FULL:
|
|
val->intval = data->energy_full;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
|
val->intval = data->capacity/100*data->energy_full;
|
|
break;
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
val->intval = data->status;
|
|
break;
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
val->intval = data->temperature * 10; // 内核温度单位为 0.1°C
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
|
val->intval = data->charge_counter;
|
|
break;
|
|
case POWER_SUPPLY_PROP_HEALTH:
|
|
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
|
break;
|
|
case POWER_SUPPLY_PROP_POWER_NOW:
|
|
val->intval = data->power_now;
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int virtual_battery_set_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
|
|
int64_t power;
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
// 验证值范围
|
|
if (val->intval < 0 || val->intval > 100) {
|
|
dev_err(&psy->dev, "Invalid capacity value: %d\n",
|
|
val->intval);
|
|
return -EINVAL;
|
|
}
|
|
data->capacity = val->intval;
|
|
break;
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
if (val->intval < POWER_SUPPLY_STATUS_UNKNOWN ||
|
|
val->intval > POWER_SUPPLY_STATUS_FULL) {
|
|
dev_err(&psy->dev, "Invalid status value: %d\n",
|
|
val->intval);
|
|
return -EINVAL;
|
|
}
|
|
data->status = val->intval;
|
|
break;
|
|
|
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
|
|
|
// 验证电压值(单位:微伏)
|
|
if (val->intval < 0 || val->intval > 13000000) { // 0-13V
|
|
dev_err(&psy->dev, "Invalid voltage: %d µV\n",
|
|
val->intval);
|
|
return -EINVAL;
|
|
}
|
|
data->voltage_now = val->intval;
|
|
power = (int64_t)data->voltage_now * abs(data->current_now);
|
|
data->power_now = (int)(power / 1000000);
|
|
dev_dbg(
|
|
&psy->dev,
|
|
"voltage_now: %d µV,current: %d µA,power:%lld,power_now:%d\n",
|
|
data->voltage_now, data->current_now, power,
|
|
data->power_now);
|
|
break;
|
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
|
// 电流可以是正(充电)或负(放电)
|
|
if (val->intval < -5000000 ||
|
|
val->intval > 5000000) { // -5A to 5A
|
|
dev_err(&psy->dev, "Invalid current: %d µA\n",
|
|
val->intval);
|
|
return -EINVAL;
|
|
}
|
|
data->current_now = val->intval;
|
|
power = (int64_t)data->voltage_now * abs(data->current_now);
|
|
data->power_now = (int)(power / 1000000);
|
|
dev_dbg(
|
|
&psy->dev,
|
|
"voltage_now: %d µV,current: %d µA,power:%lld,power_now:%d\n",
|
|
data->voltage_now, data->current_now, power,
|
|
data->power_now);
|
|
break;
|
|
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
// 温度单位是 0.1°C
|
|
if (val->intval < -200 ||
|
|
val->intval > 1000) { // -20°C 到 100°C
|
|
return -EINVAL;
|
|
}
|
|
data->temperature = val->intval;
|
|
break;
|
|
|
|
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
|
if (val->intval < 0) {
|
|
dev_err(&psy->dev, "Invalid energy: %d µWh\n",
|
|
val->intval);
|
|
return -EINVAL;
|
|
}
|
|
data->energy_now = val->intval;
|
|
break;
|
|
|
|
default:
|
|
// 对于不支持写的属性返回错误
|
|
dev_dbg(&psy->dev, "Property %d is read-only\n", psp);
|
|
return -EINVAL;
|
|
}
|
|
|
|
// 通知属性已更改
|
|
power_supply_changed(psy);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int virtual_battery_property_is_writeable(struct power_supply *psy,
|
|
enum power_supply_property psp)
|
|
{
|
|
// 指定哪些属性可写
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_CAPACITY:
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
|
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
|
case POWER_SUPPLY_PROP_TEMP:
|
|
return 1; // 可写
|
|
default:
|
|
return 0; // 只读
|
|
}
|
|
}
|
|
|
|
static int virtual_adapter_get_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
val->intval = data->online;
|
|
break;
|
|
case POWER_SUPPLY_PROP_TYPE:
|
|
val->intval = POWER_SUPPLY_TYPE_MAINS; // 交流电源
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int virtual_adapter_set_property(struct power_supply *psy,
|
|
enum power_supply_property psp,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
data->online = val->intval ? 1 : 0;
|
|
break;
|
|
default:
|
|
dev_dbg(&psy->dev, "Adapter property %d is read-only\n", psp);
|
|
return -EINVAL;
|
|
}
|
|
// 通知适配器状态变化
|
|
power_supply_changed(psy);
|
|
return 0;
|
|
}
|
|
|
|
static int virtual_adapter_property_is_writeable(struct power_supply *psy,
|
|
enum power_supply_property psp)
|
|
{
|
|
// 指定哪些属性可写
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_ONLINE:
|
|
return 1; // 可写
|
|
default:
|
|
return 0; // 只读
|
|
}
|
|
}
|
|
|
|
static const struct power_supply_desc virtual_battery_desc = {
|
|
.name = "virtual_battery",
|
|
.type = POWER_SUPPLY_TYPE_BATTERY,
|
|
.properties = virtual_battery_props,
|
|
.num_properties = ARRAY_SIZE(virtual_battery_props),
|
|
.get_property = virtual_battery_get_property,
|
|
.set_property = virtual_battery_set_property,
|
|
.property_is_writeable = virtual_battery_property_is_writeable,
|
|
|
|
};
|
|
|
|
static const struct power_supply_desc virtual_adapter_desc = {
|
|
.name = "virtual_adapter",
|
|
.type = POWER_SUPPLY_TYPE_MAINS,
|
|
.properties = virtual_adapter_props,
|
|
.num_properties = ARRAY_SIZE(virtual_adapter_props),
|
|
.get_property = virtual_adapter_get_property,
|
|
.set_property = virtual_adapter_set_property,
|
|
.property_is_writeable = virtual_adapter_property_is_writeable,
|
|
};
|
|
|
|
static int virtual_battery_probe(struct platform_device *pdev)
|
|
{
|
|
struct virtual_main_data *main_data;
|
|
struct power_supply_config psy_cfg = {};
|
|
|
|
main_data = devm_kzalloc(&pdev->dev, sizeof(*main_data), GFP_KERNEL);
|
|
if (!main_data)
|
|
return -ENOMEM;
|
|
of_property_read_u32(pdev->dev.of_node, "temperature-celsius",
|
|
&main_data->battery_data.temperature);
|
|
|
|
of_property_read_u32(pdev->dev.of_node,
|
|
"energy-full-design-microwatt-hours",
|
|
&main_data->battery_data.energy_full_design);
|
|
of_property_read_u32(pdev->dev.of_node,
|
|
"energy-full-microwatt-hours",
|
|
&main_data->battery_data.energy_full);
|
|
of_property_read_u32(pdev->dev.of_node, "capacity-now",
|
|
&main_data->battery_data.capacity);
|
|
|
|
main_data->battery_data.charge_counter = 0;
|
|
main_data->battery_data.current_now = 0;
|
|
main_data->battery_data.voltage_now = 12600000;
|
|
main_data->battery_data.energy_now = 15000000;
|
|
|
|
main_data->battery_data.power_now = 0;
|
|
main_data->battery_data.status = POWER_SUPPLY_STATUS_DISCHARGING;
|
|
|
|
psy_cfg.drv_data = &main_data->battery_data;
|
|
//psy_cfg.attr_grp = virtual_battery_groups;
|
|
main_data->battery_data.psy = devm_power_supply_register(
|
|
&pdev->dev, &virtual_battery_desc, &psy_cfg);
|
|
if (IS_ERR(main_data->battery_data.psy)) {
|
|
dev_err(&pdev->dev,
|
|
"Failed to register battery power supply\n");
|
|
return PTR_ERR(main_data->battery_data.psy);
|
|
}
|
|
|
|
main_data->adapter_data.online = 0;
|
|
psy_cfg.drv_data = &main_data->adapter_data;
|
|
//psy_cfg.attr_grp = virtual_adapter_groups;
|
|
main_data->adapter_data.psy = devm_power_supply_register(
|
|
&pdev->dev, &virtual_adapter_desc, &psy_cfg);
|
|
if (IS_ERR(main_data->adapter_data.psy)) {
|
|
dev_err(&pdev->dev,
|
|
"Failed to register adapter power supply\n");
|
|
return PTR_ERR(main_data->adapter_data.psy);
|
|
}
|
|
|
|
platform_set_drvdata(pdev, main_data);
|
|
/*
|
|
// 创建 sysfs 接口
|
|
battery_kobj =
|
|
kobject_create_and_add("virtual_battery", kernel_kobj->parent);
|
|
if (!battery_kobj) {
|
|
power_supply_unregister(virtual_battery);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = sysfs_create_group(battery_kobj, &battery_attr_group);
|
|
if (ret) {
|
|
kobject_put(battery_kobj);
|
|
power_supply_unregister(virtual_battery);
|
|
}
|
|
|
|
*/
|
|
dev_info(&pdev->dev, "Virtual battery probed successfully\n");
|
|
return 0;
|
|
}
|
|
|
|
static int virtual_battery_remove(struct platform_device *pdev)
|
|
{
|
|
dev_info(&pdev->dev, "Virtual battery removed\n");
|
|
//sysfs_remove_group(battery_kobj, &battery_attr_group);
|
|
//kobject_put(battery_kobj);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id virtual_battery_of_match[] = {
|
|
{ .compatible = "my-vendor,virtual-battery" },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, virtual_battery_of_match);
|
|
|
|
static struct platform_driver virtual_battery_driver = {
|
|
.probe = virtual_battery_probe,
|
|
.remove = virtual_battery_remove,
|
|
.driver = {
|
|
.name = "virtual_battery",
|
|
.of_match_table = virtual_battery_of_match,
|
|
},
|
|
};
|
|
|
|
module_platform_driver(virtual_battery_driver);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Ardu");
|
|
MODULE_DESCRIPTION("Virtual Battery Driver");
|
|
MODULE_VERSION("1.0"); |