SmartAudio/lichee/linux-4.9/drivers/power/supply/axp/axp-sysfs.c

374 lines
8.0 KiB
C

/*
* drivers/power/axp/axp-sysfs.c
* (C) Copyright 2010-2016
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Pannan <pannan@allwinnertech.com>
*
* axp sysfs for users
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include "axp-core.h"
static int axp_num;
static ssize_t axp_num_show(struct class *class,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "pmu%d\n", axp_num);
}
static ssize_t axp_num_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int val, err;
err = kstrtoint(buf, 16, &val);
if (err)
return err;
axp_num = val;
if ((axp_num >= AXP_ONLINE_SUM) || (axp_num < 0))
return -EINVAL;
return count;
}
static ssize_t axp_name_show(struct class *class,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", get_pmu_cur_name(axp_num));
}
static u8 axp_reg_addr;
static ssize_t axp_reg_show(struct class *class,
struct class_attribute *attr, char *buf)
{
u8 val;
struct axp_dev *cur_axp_dev = get_pmu_cur_dev(axp_num);
if (cur_axp_dev == NULL)
return sprintf(buf, "invalid parameters\n");
if (cur_axp_dev->is_dummy)
return sprintf(buf, "unsupported\n");
axp_regmap_read(cur_axp_dev->regmap, axp_reg_addr, &val);
return sprintf(buf, "%s:REG[0x%x]=0x%x\n",
get_pmu_cur_name(axp_num), axp_reg_addr, val);
}
static ssize_t axp_reg_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
s32 tmp;
u8 val;
int err;
struct axp_dev *cur_axp_dev = get_pmu_cur_dev(axp_num);
if (cur_axp_dev == NULL) {
pr_warn("invalid parameters\n");
return -EINVAL;
}
if (cur_axp_dev->is_dummy) {
pr_err("unsupported\n");
return -EINVAL;
}
err = kstrtoint(buf, 16, &tmp);
if (err)
return err;
if (tmp < 256) {
axp_reg_addr = tmp;
} else {
val = tmp & 0x00FF;
axp_reg_addr = (tmp >> 8) & 0x00FF;
axp_regmap_write(cur_axp_dev->regmap, axp_reg_addr, val);
}
return count;
}
static u32 axp_regs_data_size = 2;
static ssize_t axp_regs_show(struct class *class,
struct class_attribute *attr, char *buf)
{
u8 val;
s32 count = 0, i = 0;
struct axp_dev *cur_axp_dev = get_pmu_cur_dev(axp_num);
if (cur_axp_dev == NULL)
return sprintf(buf, "invalid parameters\n");
if (cur_axp_dev->is_dummy)
return sprintf(buf, "unsupported\n");
for (i = 0; i < axp_regs_data_size; i++) {
axp_regmap_read(cur_axp_dev->regmap, axp_reg_addr+i, &val);
count += sprintf(buf+count, "%s:REG[0x%x]=0x%x\n",
get_pmu_cur_name(axp_num), axp_reg_addr+i, val);
}
return count;
}
static ssize_t axp_regs_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
u32 data1 = 0;
u8 val[2];
char *endp;
struct axp_dev *cur_axp_dev = get_pmu_cur_dev(axp_num);
if (cur_axp_dev == NULL) {
pr_warn("invalid parameters\n");
return -EINVAL;
}
if (cur_axp_dev->is_dummy) {
pr_err("unsupported\n");
return -EINVAL;
}
data1 = simple_strtoul(buf, &endp, 16);
if (*endp != ' ') {
pr_err("%s: %d\n", __func__, __LINE__);
return -EINVAL;
}
buf = endp + 1;
axp_regs_data_size = simple_strtoul(buf, &endp, 10);
if (data1 < 256) {
axp_reg_addr = data1;
} else {
axp_reg_addr = (data1 >> 16) & 0xFF;
val[0] = (data1 >> 8) & 0xFF;
val[1] = data1 & 0xFF;
axp_regmap_writes(cur_axp_dev->regmap, axp_reg_addr, 2, val);
}
return count;
}
int axp_debug_mask;
static ssize_t debugmask_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int val, err;
err = kstrtoint(buf, 16, &val);
if (err)
return err;
axp_debug_mask = val;
return count;
}
static ssize_t debugmask_show(struct class *class,
struct class_attribute *attr, char *buf)
{
char *s = buf;
char *end = (char *)((ptrdiff_t)buf + (ptrdiff_t)PAGE_SIZE);
s += scnprintf(s, end - s, "%s\n", "1: SPLY 2: REGU 4: INT 8: CHG");
s += scnprintf(s, end - s, "debug_mask=%d\n", axp_debug_mask);
return s - buf;
}
static ssize_t add_sys_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int name_len;
const char *arg;
char sys_name[20] = {0};
/* Find length of lock name */
arg = buf;
while (*arg && !isspace(*arg))
arg++;
name_len = arg - buf;
if ((!name_len) && (name_len > 20))
goto bad_arg;
strncpy(sys_name, buf, name_len);
axp_add_sys_pwr_dm(sys_name);
return count;
bad_arg:
pr_err("%s para error.\n", __func__);
return count;
}
static ssize_t del_sys_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int name_len;
const char *arg;
char sys_name[20] = {0};
/* Find length of lock name */
arg = buf;
while (*arg && !isspace(*arg))
arg++;
name_len = arg - buf;
if ((!name_len) && (name_len > 20))
goto bad_arg;
strncpy(sys_name, buf, name_len);
axp_del_sys_pwr_dm(sys_name);
return count;
bad_arg:
pr_err("%s para error.\n", __func__);
return count;
}
static ssize_t get_sys_show(struct class *class,
struct class_attribute *attr, char *buf)
{
ssize_t count = 0;
count += sprintf(buf+count, "0x%x\n", axp_get_sys_pwr_dm_mask());
return count;
}
char check_sys_name[20] = {0};
static ssize_t check_sys_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int name_len;
const char *arg;
/* Find length of lock name */
arg = buf;
while (*arg && !isspace(*arg))
arg++;
name_len = arg - buf;
if ((!name_len) && (name_len > 20))
goto bad_arg;
strncpy(check_sys_name, buf, name_len);
return count;
bad_arg:
pr_err("%s para error.\n", __func__);
return count;
}
static ssize_t check_sys_show(struct class *class,
struct class_attribute *attr, char *buf)
{
s32 sys_id_conut = 0, ret = 0;
ssize_t count = 0;
char ldo_name[20] = {0};
if (check_sys_name == NULL) {
pr_err("please input sys name\n");
return -1;
}
sys_id_conut = axp_check_sys_id(check_sys_name);
if (sys_id_conut < 0) {
pr_err("%s: %s not sys id.\n", __func__, check_sys_name);
return -1;
}
ret = axp_get_ldo_name(check_sys_name, (char *)&ldo_name);
if (ret < 0) {
pr_err("%s: get ldo name for id: %s failed\n",
__func__, check_sys_name);
return -1;
}
ret = axp_is_sys_pwr_dm_active(sys_id_conut);
count += sprintf(buf+count, "%d\n", ret);
return count;
}
static struct class_attribute axp_class_attrs[] = {
__ATTR(axp_name, S_IRUGO, axp_name_show, NULL),
__ATTR(axp_num, S_IRUGO|S_IWUSR, axp_num_show, axp_num_store),
__ATTR(axp_reg, S_IRUGO|S_IWUSR, axp_reg_show, axp_reg_store),
__ATTR(axp_regs, S_IRUGO|S_IWUSR, axp_regs_show, axp_regs_store),
__ATTR(debug_mask, S_IRUGO|S_IWUSR, debugmask_show, debugmask_store),
__ATTR(sys_pwr_add, S_IWUSR, NULL, add_sys_store),
__ATTR(sys_pwr_del, S_IWUSR, NULL, del_sys_store),
__ATTR(sys_pwr_get, S_IRUGO, get_sys_show, NULL),
__ATTR(sys_pwr_check, S_IRUGO|S_IWUSR, check_sys_show, check_sys_store),
__ATTR_NULL
};
struct class axp_class = {
.name = "axp",
.class_attrs = axp_class_attrs,
};
#ifdef CONFIG_AXP_TWI_USED
#include <linux/reboot.h>
#include <linux/cpufreq.h>
static int axp_reboot_notifier_call(struct notifier_block *this,
unsigned long code, void *_cmd)
{
disable_cpufreq();
return NOTIFY_DONE;
}
static struct notifier_block axp_reboot_notifier = {
.notifier_call = axp_reboot_notifier_call,
};
#endif
static int __init axp_sysfs_init(void)
{
int status;
#ifdef CONFIG_AXP_TWI_USED
register_reboot_notifier(&axp_reboot_notifier);
#endif
status = class_register(&axp_class);
if (status < 0)
pr_err("%s,%d err, status:%d\n", __func__, __LINE__, status);
return status;
}
arch_initcall(axp_sysfs_init);
static void __exit axp_sysfs_exit(void)
{
class_unregister(&axp_class);
}
module_exit(axp_sysfs_exit);
MODULE_DESCRIPTION("ALLWINNERTECH axp sysfs");
MODULE_AUTHOR("pannan");
MODULE_LICENSE("GPL");