374 lines
8.0 KiB
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");
|