M7350/kernel/arch/arm/mach-msm/pm8019_ext.c
2024-09-09 08:52:07 +00:00

206 lines
4.9 KiB
C
Executable File

/*****************************************************************************
* Copyright (C), 2002-2014, TP-LINK TECHNOLOGIES CO., LTD.
*
* File Name: pm8019_ext.c
* Version: 1.0
* Description: Export some PM8019 software interfaces to sysfs.
*
* Author: LuoWei
* Create Date: 2014-04-10
*
* History:
* 01 10Apr14 LuoWei Create file
*****************************************************************************/
#include <linux/kobject.h>
#include <include/mach/msm_smem.h>
#include <linux/gpio.h>
#include <linux/stat.h>
#include "pm8019_ext.h"
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long long uint64;
/* [ouyangyi] add power on info */
char int_to_hex_char(int v)
{
if (v >= 0 && v < 10)
{
return ('0' + v);
}
else if (v >= 10 && v < 16)
{
return ('A' + v - 10);
}
else
{
return 0;
}
}
#define PMIC_PON_INFO_HEX_BITS 16
static ssize_t pmic_pon_info_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
uint64 pon_info = 0;
unsigned int size = 0;
int i = 0;
pon_info = *(uint64 *)smem_get_entry(SMEM_POWER_ON_STATUS_INFO, &size);
if (!size || !pon_info) {
pr_err("%s: Cannot get the pon_info\n", __func__);
return sprintf(buf, "0000000000000000\n");
}
for (i = 0; i < PMIC_PON_INFO_HEX_BITS; i++) {
buf[PMIC_PON_INFO_HEX_BITS - i - 1] =
int_to_hex_char((int)(pon_info & 0xF));
pon_info = pon_info >> 4;
}
buf[PMIC_PON_INFO_HEX_BITS] = '\n';
return (PMIC_PON_INFO_HEX_BITS + 1);
}
static struct kobj_attribute pmic_pon_info_attr = {
.attr = {
.name = "pon_info",
.mode = S_IRUGO,
},
.show = &pmic_pon_info_show,
};
static struct attribute *pmic_pon_info_attrs[] = {
&pmic_pon_info_attr.attr,
NULL
};
static struct attribute_group pmic_pon_info_attr_group = {
.attrs = pmic_pon_info_attrs,
};
/* [ouyangyi] add end */
#define PM_TRIGGER_BIT_START 1
#define PM_TRIGGER_BIT_END 9
/*
The function shows one byte of power on reason for User Level.
The power on reason struct is :
typedef struct
{
unsigned hard_reset : 1; //Hard reset event trigger
unsigned smpl : 1; //SMPL trigger
unsigned rtc : 1; //RTC trigger
unsigned dc_chg : 1; //DC Charger trigger
unsigned usb_chg : 1; //USB Charger trigger
unsigned pon1 : 1; //PON1 trigger
unsigned cblpwr : 1; //CBL_PWR1_N trigger
unsigned kpdpwr : 1; //KPDPWR_N trigger
}pm_pon_pon_reason_type;
buf[0] buf[1] buf[2] ... buf[8]
is reset hard_reset smpl ... kpdpwr
*/
static ssize_t pmic_pon_trigger_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
static int first_time = 1;
static uint64 reason = 0;
static unsigned int size = 0;
uint8 pon_reason = 0;
uint16 warm_reset_reason = 0;
uint16 soft_reset_reason = 0;
int i = 0;
if (first_time) {
first_time = 0;
/*
* There are 8 bytes in field SMEM_POWER_ON_STATUS_INFO, which contains
* reasons for Power On(1 byte), Warm Reset(2 bytes), Power Off(2 bytes)
* , Soft Reset(2 bytes) and reserved byte(1 byte).
* The system is Litter-Endian, the last byte is power on reason.
*/
reason = *(uint64 *)smem_get_entry(SMEM_POWER_ON_STATUS_INFO,
&size);
}
if (!size || !reason) {
pr_err("%s: Cannot get the reasons\n", __func__);
return sprintf(buf, "000000000\n");
}
pon_reason = (reason & 0xFF);
warm_reset_reason = (reason >> (1 * 8)) & 0xFFFF;
soft_reset_reason = (reason >> ((1 + 2 + 2) * 8)) & 0xFFFF;
if (warm_reset_reason || soft_reset_reason) {
buf[0] = '1';
} else {
buf[0] = '0';
}
for (i = PM_TRIGGER_BIT_START; i < PM_TRIGGER_BIT_END; i++) {
if (pon_reason & (1 << (i - PM_TRIGGER_BIT_START))) {
buf[i] = '1';
} else {
buf[i] = '0';
}
}
buf[PM_TRIGGER_BIT_END] = '\n';
return PM_TRIGGER_BIT_END + 1;
}
/*
* Export sysfs interface.
* "cat /sys/pmic/pon_trigger" shows the power-on reason
*/
static struct kobj_attribute pmic_trigger_attr = {
.attr = {
.name = "pon_trigger",
.mode = S_IRUGO,
},
.show = &pmic_pon_trigger_show,
};
static struct attribute *pmic_trigger_attrs[] = {
&pmic_trigger_attr.attr,
NULL
};
static struct attribute_group pmic_trigger_attr_group = {
.attrs = pmic_trigger_attrs,
};
void export_pmic_interface(void)
{
struct kobject* kobj;
int ret;
kobj = kobject_create_and_add("pmic", NULL);
if (!kobj) {
pr_err("%s: failed to export PMIC interface\n", __func__);
return;
}
ret = sysfs_create_group(kobj, &pmic_trigger_attr_group);
if (!kobj || ret) {
pr_err("%s: failed to export PMIC trigger interface\n", __func__);
}
ret = sysfs_create_group(kobj, &pmic_pon_info_attr_group);
if (!kobj || ret) {
pr_err("%s: failed to export PMIC pon_info interface\n", __func__);
}
}