aboutsummaryrefslogtreecommitdiff
path: root/kernel/power/user_sysfs_private.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/user_sysfs_private.c')
-rw-r--r--kernel/power/user_sysfs_private.c1375
1 files changed, 1375 insertions, 0 deletions
diff --git a/kernel/power/user_sysfs_private.c b/kernel/power/user_sysfs_private.c
new file mode 100644
index 00000000..e226d55f
--- /dev/null
+++ b/kernel/power/user_sysfs_private.c
@@ -0,0 +1,1375 @@
+/*
+* Copyright (C) 2012 lenovo, Inc.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h> /* sys_sync */
+#include <linux/rtc.h> /* sys_sync */
+/* yangjq, 2011-12-16, Add for vreg, START */
+#include <linux/platform_device.h>
+/* yangjq, 2011-12-16, Add for vreg, END */
+#include <linux/err.h>
+////#include <mach/pmic.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+
+static u32 *tz_config = NULL;
+static int tz_pin_num = 0;
+static struct kobject *sysfs_private_kobj;
+
+#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
+ ((((gpio) & 0x3FF) << 4) | \
+ ((func) & 0xf) | \
+ (((dir) & 0x1) << 14) | \
+ (((pull) & 0x3) << 15) | \
+ (((drvstr) & 0xF) << 17))
+
+/* GP PIN TYPE REG MASKS */
+#define TLMM_GP_DRV_SHFT 6
+#define TLMM_GP_DRV_MASK 0x7
+#define TLMM_GP_PULL_SHFT 0
+#define TLMM_GP_PULL_MASK 0x3
+#define TLMM_GP_DIR_SHFT 9
+#define TLMM_GP_DIR_MASK 1
+#define TLMM_GP_FUNC_SHFT 2
+#define TLMM_GP_FUNC_MASK 0xF
+#define GPIO_OUT_BIT 1
+#define GPIO_IN_BIT 0
+#define GPIO_OE_BIT 9
+/**
+ * extract GPIO pin from bit-field used for gpio_tlmm_config
+ */
+#define GPIO_PIN(gpio_cfg) (((gpio_cfg) >> 4) & 0x3ff)
+#define GPIO_FUNC(gpio_cfg) (((gpio_cfg) >> 0) & 0xf)
+#define GPIO_DIR(gpio_cfg) (((gpio_cfg) >> 14) & 0x1)
+#define GPIO_PULL(gpio_cfg) (((gpio_cfg) >> 15) & 0x3)
+#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
+#define TLMM_GP_CFG(reg_base, pin) (reg_base + 0x0 + \
+ 0x1000* (pin))
+#define TLMM_GP_INOUT(reg_base, pin) (reg_base + 0x4 + \
+ 0x1000 * (pin))
+/* chenyb1, 20130515, Add sysfs for gpio's debug, START */
+#define TLMM_NUM_GPIO 141
+
+#define HAL_OUTPUT_VAL(config) \
+ (((config)&0x40000000)>>30)
+
+extern void *tlmm_reg_base;
+static int tlmm_get_cfg(unsigned gpio, unsigned* cfg)
+{
+ unsigned flags;
+
+ if(tlmm_reg_base == NULL)
+ return -1;
+ BUG_ON(gpio >= TLMM_NUM_GPIO);
+ //printk("%s(), gpio=%d, addr=0x%08x\n", __func__, gpio, (unsigned int)GPIO_CONFIG(gpio));
+
+#if 0
+ flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
+ ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
+ ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
+ ((GPIO_PULL(config) & 0x3));
+#else
+ flags = readl_relaxed(TLMM_GP_CFG(tlmm_reg_base, gpio));
+#endif
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ *cfg = GPIO_CFG(gpio, (flags >> TLMM_GP_FUNC_SHFT) & 0xf, (flags >> TLMM_GP_DIR_SHFT) & 0x1, flags & 0x3, (flags >> TLMM_GP_DRV_SHFT) & 0x7);
+
+ return 0;
+}
+
+int tlmm_set_config(unsigned config)
+{
+ unsigned int flags;
+ unsigned gpio = GPIO_PIN(config);
+ void __iomem *cfg_reg = TLMM_GP_CFG(tlmm_reg_base, gpio );
+
+ if(tlmm_reg_base == NULL)
+ return -1;
+ if (gpio > TLMM_NUM_GPIO)
+ return -EINVAL;
+
+ printk("%s(), %d,gpio=%d\n", __func__, __LINE__, gpio);
+
+ config = (config & ~0x40000000);
+ flags = readl_relaxed(cfg_reg);
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+
+ flags = ((GPIO_DIR(config) & TLMM_GP_DIR_MASK) << TLMM_GP_DIR_SHFT) |
+ ((GPIO_DRVSTR(config) & TLMM_GP_DRV_MASK) << TLMM_GP_DRV_SHFT) |
+ ((GPIO_FUNC(config) & TLMM_GP_FUNC_MASK) << TLMM_GP_FUNC_SHFT) |
+ ((GPIO_PULL(config) & TLMM_GP_PULL_MASK));
+
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ writel_relaxed(flags, cfg_reg);
+
+#if 0
+ /*set func*/
+ cfg_reg = TLMMV4_GP_CFG(tlmm_reg_base, gpio);
+ flags = readl_relaxed(cfg_reg);
+ flags &= ~(TLMMV4_GP_FUNC_MASK << TLMMV4_GP_FUNC_SHFT);
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+
+ flags |= (GPIO_FUNC(config) << TLMMV4_GP_FUNC_SHFT);
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ writel_relaxed(flags, cfg_reg);
+
+ /* set DIR */
+ cfg_reg = TLMMV4_GP_CFG(tlmm_reg_base, gpio);
+ flags = readl_relaxed(cfg_reg);
+ if (GPIO_DIR(config))
+ {
+ flags |= BIT(GPIO_OE_BIT);
+ }
+ else
+ {
+ flags &= ~BIT(GPIO_OE_BIT);
+ }
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ writel_relaxed(flags, cfg_reg);
+
+ /* set PULL */
+ flags = readl_relaxed(cfg_reg);
+ flags |= GPIO_PULL(config) & 0x3;
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ writel_relaxed(flags, cfg_reg);
+
+ /* set DRVSTR */
+ flags = readl_relaxed(cfg_reg);
+ flags |= drv_str_to_rval(GPIO_DRVSTR(config));
+ printk("%s(), %d, flags=%x\n", __func__, __LINE__, flags);
+ writel_relaxed(flags, cfg_reg);
+#endif
+ return 0;
+}
+static int tlmm_dump_cfg(char* buf,unsigned gpio, unsigned cfg, int output_val)
+{
+ static char* drvstr_str[] = { "2", "4", "6", "8", "10", "12", "14", "16" }; // mA
+ static char* pull_str[] = { "N", "D", "K", "U" }; // "NO_PULL", "PULL_DOWN", "KEEPER", "PULL_UP"
+ static char* dir_str[] = { "I", "O" }; // "Input", "Output"
+ char func_str[20];
+
+ char* p = buf;
+
+ int drvstr = GPIO_DRVSTR(cfg);
+ int pull = GPIO_PULL(cfg);
+ int dir = GPIO_DIR(cfg);
+ int func = GPIO_FUNC(cfg);
+
+ //printk("%s(), drvstr=%d, pull=%d, dir=%d, func=%d\n", __func__, drvstr, pull, dir, func);
+ sprintf(func_str, "%d", func);
+
+ p += sprintf(p, "%d:0x%x %s%s%s%s", gpio, cfg,
+ func_str, pull_str[pull], dir_str[dir], drvstr_str[drvstr]);
+
+ p += sprintf(p, " = %d", output_val);
+
+ p += sprintf(p, "\n");
+
+ return p - buf;
+}
+
+static int tlmm_dump_header(char* buf)
+{
+ char* p = buf;
+ p += sprintf(p, "bit 0~3: function. (0 is GPIO)\n");
+ p += sprintf(p, "bit 4~13: gpio number\n");
+ p += sprintf(p, "bit 14: 0: input, 1: output\n");
+ p += sprintf(p, "bit 15~16: pull: NO_PULL, PULL_DOWN, KEEPER, PULL_UP\n");
+ p += sprintf(p, "bit 17~20: driver strength. \n");
+ p += sprintf(p, "0:GPIO\n");
+ p += sprintf(p, "N:NO_PULL D:PULL_DOWN K:KEEPER U:PULL_UP\n");
+ p += sprintf(p, "I:Input O:Output\n");
+ p += sprintf(p, "2:2, 4, 6, 8, 10, 12, 14, 16 mA (driver strength)\n\n");
+ return p - buf;
+}
+
+static int tlmm_get_inout(unsigned gpio)
+{
+ void __iomem *inout_reg = TLMM_GP_INOUT(tlmm_reg_base, gpio);
+
+ if(tlmm_reg_base == NULL)
+ return -1;
+ return readl_relaxed(inout_reg) & BIT(GPIO_IN_BIT);
+}
+
+void tlmm_set_inout(unsigned gpio, unsigned val)
+{
+ void __iomem *inout_reg = TLMM_GP_INOUT(tlmm_reg_base, gpio);
+
+ if(tlmm_reg_base == NULL)
+ return;
+ writel_relaxed(val ? BIT(GPIO_OUT_BIT) : 0, inout_reg);
+}
+
+int tlmm_dump_info(char* buf, int tlmm_num)
+{
+ unsigned i, j;
+ char* p = buf;
+ unsigned cfg;
+ int output_val = 0;
+ int tz_flag = 0;
+
+ if(tlmm_num >= 0 && tlmm_num < TLMM_NUM_GPIO) {
+ tlmm_get_cfg(tlmm_num, &cfg);
+ output_val = tlmm_get_inout(tlmm_num);
+
+ p += tlmm_dump_cfg(p, tlmm_num, cfg, output_val);
+ } else {
+
+ p += tlmm_dump_header(p);
+ p += sprintf(p, "Standard Format: gpio_num function pull direction strength [output_value]\n");
+ p += sprintf(p, "Shortcut Format: gpio_num output_value\n");
+ p += sprintf(p, " e.g. 'echo 20 0 D O 2 1' ==> set pin 20 as GPIO output and the output = 1 \n");
+ p += sprintf(p, " e.g. 'echo 20 1' ==> set output gpio pin 20 output = 1 \n");
+ printk("%s(), %d, TLMM_BASE=%lx\n", __func__, __LINE__, (unsigned long int)(void *)tlmm_reg_base);
+ for(i = 0; i < TLMM_NUM_GPIO; ++i) {
+ for(j = 0; j < tz_pin_num; j++) {
+ if(i == tz_config[j]) {
+ tz_flag = 1;
+ continue;
+ }
+ }
+ if(tz_flag == 1) {
+ tz_flag = 0;
+ continue;
+ }
+ tlmm_get_cfg(i, &cfg);
+ output_val = tlmm_get_inout(i);
+
+ p += tlmm_dump_cfg(p, i, cfg, output_val);
+ }
+ printk("%s(), %d\n", __func__, __LINE__);
+ p+= sprintf(p, "(%ld)\n", (unsigned long)(p - buf)); // only for debug reference
+ }
+ return p - buf;
+}
+
+/* save tlmm config before sleep */
+static int before_sleep_fetched;
+module_param(before_sleep_fetched,int,0644);
+static unsigned before_sleep_configs[TLMM_NUM_GPIO];
+void tlmm_before_sleep_save_configs(void)
+{
+ unsigned i;
+
+ //only save tlmm configs when it has been fetched
+ if (!before_sleep_fetched)
+ return;
+
+ printk("%s(), before_sleep_fetched=%d\n", __func__, before_sleep_fetched);
+ before_sleep_fetched = false;
+ for(i = 0; i < TLMM_NUM_GPIO; ++i) {
+ unsigned cfg;
+ int output_val = 0;
+
+ tlmm_get_cfg(i, &cfg);
+ output_val = tlmm_get_inout(i);
+
+ before_sleep_configs[i] = cfg | (output_val << 30);
+ }
+}
+
+int tlmm_before_sleep_dump_info(char* buf)
+{
+ unsigned i;
+ char* p = buf;
+
+ p += sprintf(p, "tlmm_before_sleep:\n");
+ if (!before_sleep_fetched) {
+ before_sleep_fetched = true;
+
+ p += tlmm_dump_header(p);
+
+ for(i = 0; i < TLMM_NUM_GPIO; ++i) {
+ unsigned cfg;
+ int output_val = 0;
+
+ cfg = before_sleep_configs[i];
+ output_val = HAL_OUTPUT_VAL(cfg);
+ //cfg &= ~0x40000000;
+ p += tlmm_dump_cfg(p, i, cfg, output_val);
+ }
+ p+= sprintf(p, "(%ld)\n", (unsigned long)(p - buf)); // only for debug reference
+ }
+ return p - buf;
+}
+
+/* set tlmms config before sleep */
+static int before_sleep_table_enabled = 0;
+module_param(before_sleep_table_enabled,int,0644);
+static unsigned before_sleep_table_configs[TLMM_NUM_GPIO];
+void tlmm_before_sleep_set_configs(void)
+{
+ int res;
+ unsigned i;
+
+ //only set tlmms before sleep when it's enabled
+ if (!before_sleep_table_enabled)
+ return;
+
+ printk("%s(), before_sleep_table_enabled=%d\n", __func__, before_sleep_table_enabled);
+ for(i = 0; i < TLMM_NUM_GPIO; ++i) {
+ unsigned cfg;
+ int gpio;
+ int dir;
+ int func;
+ int output_val = 0;
+
+ cfg = before_sleep_table_configs[i];
+
+ gpio = GPIO_PIN(cfg);
+ if(gpio != i)//(cfg & ~0x20000000) == 0 ||
+ continue;
+
+ output_val = HAL_OUTPUT_VAL(cfg);
+ //Clear the output value
+ //cfg &= ~0x40000000;
+ dir = GPIO_DIR(cfg);
+ func = GPIO_FUNC(cfg);
+
+ printk("%s(), [%d]: 0x%x\n", __func__, i, cfg);
+ res = tlmm_set_config(cfg & ~0x40000000);
+ if(res < 0) {
+ printk("Error: Config failed.\n");
+ }
+
+ if((func == 0) && (dir == 1)) // gpio output
+ tlmm_set_inout(i, output_val);
+ }
+}
+
+int tlmm_before_sleep_table_set_cfg(unsigned gpio, unsigned cfg)
+{
+ //BUG_ON(gpio >= TLMM_NUM_GPIO && GPIO_PIN(cfg) != 0xff);
+ if (gpio >= TLMM_NUM_GPIO && gpio != 255 && gpio != 256) {
+ printk("gpio >= TLMM_NUM_GPIO && gpio != 255 && gpio != 256!\n");
+ return -1;
+ }
+
+ if(gpio < TLMM_NUM_GPIO)
+ {
+ before_sleep_table_configs[gpio] = cfg;// | 0x20000000
+ before_sleep_table_enabled = true;
+ }
+ else if(gpio == 255)
+ before_sleep_table_enabled = true;
+ else if(gpio == 256)
+ before_sleep_table_enabled = false;
+
+ return 0;
+}
+
+int tlmm_before_sleep_table_dump_info(char* buf)
+{
+ unsigned i;
+ char* p = buf;
+
+ p += tlmm_dump_header(p);
+ p += sprintf(p, "Format: gpio_num function pull direction strength [output_value]\n");
+ p += sprintf(p, " e.g. 'echo 20 0 D O 2 1' ==> set pin 20 as GPIO output and the output = 1 \n");
+ p += sprintf(p, " e.g. 'echo 20' ==> disable pin 20's setting \n");
+ p += sprintf(p, " e.g. 'echo 255' ==> enable sleep table's setting \n");
+ p += sprintf(p, " e.g. 'echo 256' ==> disable sleep table's setting \n");
+
+ for(i = 0; i < TLMM_NUM_GPIO; ++i) {
+ unsigned cfg;
+ int output_val = 0;
+
+ cfg = before_sleep_table_configs[i];
+ output_val = HAL_OUTPUT_VAL(cfg);
+ //cfg &= ~0x40000000;
+ p += tlmm_dump_cfg(p, i, cfg, output_val);
+ }
+ p+= sprintf(p, "(%ld)\n", (unsigned long)(p - buf)); // only for debug reference
+ return p - buf;
+}
+/* yangjq, 20130515, Add sysfs for gpio's debug, END */
+
+
+#define private_attr(_name) \
+static struct kobj_attribute _name##_attr = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644, \
+ }, \
+ .show = _name##_show, \
+ .store = _name##_store, \
+}
+
+#ifdef CONFIG_LENOVO_PM_LOG_TLMM//TBD
+//chenyb1, 2015-2-3, Add a sysfs interface for modem's sim card checking, START
+#define TLMM_GPIO_SIM 60
+static ssize_t tlmm_sim_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char *p = buf;
+ int output_val = 0;
+
+ output_val = tlmm_get_inout(TLMM_GPIO_SIM);
+ p += sprintf(p, "%d", output_val);
+
+ return (p - buf);
+}
+
+static ssize_t tlmm_sim_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support yet.\n", __func__);
+
+ return -EPERM;
+}
+//yangjq, 2015-2-3, Add a sysfs interface for modem's sim card checking, END
+
+static int tlmm_num = -1;
+static ssize_t tlmm_num_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+ p += sprintf(p, "A single gpio[0, %d] to be checked by cat tlmm\n", TLMM_NUM_GPIO);
+ p += sprintf(p, "-1 to check all %d gpios by cat tlmm\n", TLMM_NUM_GPIO+1);
+ p += sprintf(p, "%d\n", tlmm_num);
+ p += sprintf(p, "TLMM_BASE=%lx\n", (unsigned long int)(void *)tlmm_reg_base);
+
+ printk("%s(), %d, TLMM_BASE=%lx\n", __func__, __LINE__, (unsigned long int)(void *)tlmm_reg_base);
+ return p - buf;
+}
+
+static ssize_t tlmm_num_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int gpio;
+ int res;
+
+ res = sscanf(buf, "%d", &gpio);
+ printk("res=%d. %d\n", res, gpio);
+
+ if(res != 1)
+ goto tlmm_num_store_wrong_para;
+
+ if(gpio >= TLMM_NUM_GPIO)
+ goto tlmm_num_store_wrong_para;
+
+ tlmm_num = gpio;
+ printk("tlmm_num: %d\n", tlmm_num);
+
+ goto tlmm_num_store_ok;
+
+tlmm_num_store_wrong_para:
+ printk("Wrong Input.\n");
+ printk("Format: gpio_num\n");
+ printk(" gpio_num: 0 ~ 145\n");
+
+tlmm_num_store_ok:
+ return n;
+}
+
+static ssize_t tlmm_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+#if 1 //TBD
+ p += tlmm_dump_info(buf, tlmm_num);
+#endif
+ return p - buf;
+}
+
+static ssize_t tlmm_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ char pull_c, dir_c;
+ int gpio, func, pull, dir, drvstr, output_val;
+ unsigned cfg;
+ int res;
+
+ res = sscanf(buf, "%d %d %c %c %d %d", &gpio, &func, &pull_c, &dir_c, &drvstr, &output_val);
+ printk("res=%d. %d %d %c %c %d %d\n", res, gpio, func, pull_c, dir_c, drvstr, output_val);
+
+ //Add a shortcut wrting format to change an output gpio's value
+ if(res == 2 && gpio < TLMM_NUM_GPIO && (func == 0 || func == 1)) {
+ output_val = func;
+ goto tlmm_store_only_output_val;
+ }
+ if((res != 5) && (res != 6))
+ goto tlmm_store_wrong_para;
+
+ if(gpio >= TLMM_NUM_GPIO)
+ goto tlmm_store_wrong_para;
+
+ if('N' == pull_c)
+ pull = 0;
+ else if('D' == pull_c)
+ pull = 1;
+ else if('K' == pull_c)
+ pull = 2;
+ else if('U' == pull_c)
+ pull = 3;
+ else
+ goto tlmm_store_wrong_para;
+
+ if('I' == dir_c)
+ dir = 0;
+ else if('O' == dir_c)
+ dir = 1;
+ else
+ goto tlmm_store_wrong_para;
+
+ drvstr = drvstr/2 - 1; // 2mA -> 0, 4mA -> 1, 6mA -> 2, ...
+ if(drvstr > 7)
+ goto tlmm_store_wrong_para;
+
+ if(output_val > 1)
+ goto tlmm_store_wrong_para;
+
+ printk("final set: %d %d %d %d %d %d\n", gpio, func, pull, dir, drvstr, output_val);
+
+ cfg = GPIO_CFG(gpio, func, dir, pull, drvstr);
+#if 1
+ res = tlmm_set_config(cfg);
+ if(res < 0) {
+ printk("Error: Config failed.\n");
+ goto tlmm_store_wrong_para;
+ }
+#endif
+ printk("final set: %d %d %d %d %d %d\n", gpio, func, pull, dir, drvstr, output_val);
+ if((func == 0) && (dir == 1)) // gpio output
+tlmm_store_only_output_val:
+ tlmm_set_inout(gpio, output_val);
+
+ goto tlmm_store_ok;
+
+tlmm_store_wrong_para:
+ printk("Wrong Input.\n");
+ printk("Standard Format: gpio_num function pull direction strength [output_value]\n");
+ printk("Shortcut Format: gpio_num output_value\n");
+ printk(" gpio_num: 0 ~ 145\n");
+ printk(" function: number, where 0 is GPIO\n");
+ printk(" pull: 'N': NO_PULL, 'D':PULL_DOWN, 'K':KEEPER, 'U': PULL_UP\n");
+ printk(" direction: 'I': Input, 'O': Output\n");
+ printk(" strength: 2, 4, 6, 8, 10, 12, 14, 16\n");
+ printk(" output_value: Optional. 0 or 1. vaild if GPIO output\n");
+ printk(" e.g. 'echo 20 0 D I 2' ==> set pin 20 as GPIO input \n");
+ printk(" e.g. 'echo 20 0 D O 2 1' ==> set pin 20 as GPIO output and the output = 1 \n");
+ printk(" e.g. 'echo 20 1' ==> set output gpio pin 20 output = 1 \n");
+
+tlmm_store_ok:
+ return n;
+}
+
+/* Set GPIO's sleep config from sysfs */
+static ssize_t tlmm_before_sleep_table_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+#if 1 //TBD
+ p += tlmm_before_sleep_table_dump_info(buf);
+#endif
+ return p - buf;
+}
+
+static ssize_t tlmm_before_sleep_table_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ char pull_c, dir_c;
+ int gpio, func = 0, pull = 0, dir = 0, drvstr = 0, output_val = 0;
+ int ignore;
+ unsigned cfg;
+ int res;
+
+ res = sscanf(buf, "%d %d %c %c %d %d", &gpio, &func, &pull_c, &dir_c, &drvstr, &output_val);
+ printk("res=%d. %d %d %c %c %d %d\n", res, gpio, func, pull_c, dir_c, drvstr, output_val);
+
+ if(1 == res) { // if only gpio, means ingore(disable) the gpio's sleep config
+ ignore = 1;
+ printk("final set: to disable gpio %d sleep config\n", gpio);
+ }
+ else {
+ ignore = 0;
+
+ if((res != 5) && (res != 6))
+ goto tlmm_before_sleep_table_store_wrong_para;
+
+ if(gpio >= TLMM_NUM_GPIO)
+ goto tlmm_before_sleep_table_store_wrong_para;
+
+ if('N' == pull_c)
+ pull = 0;
+ else if('D' == pull_c)
+ pull = 1;
+ else if('K' == pull_c)
+ pull = 2;
+ else if('U' == pull_c)
+ pull = 3;
+ else
+ goto tlmm_before_sleep_table_store_wrong_para;
+
+ if('I' == dir_c)
+ dir = 0;
+ else if('O' == dir_c)
+ dir = 1;
+ else
+ goto tlmm_before_sleep_table_store_wrong_para;
+
+ drvstr = drvstr/2 - 1; // 2mA -> 0, 4mA -> 1, 6mA -> 2, ...
+ if(drvstr > 7)
+ goto tlmm_before_sleep_table_store_wrong_para;
+
+ printk("final set: %d %d %d %d %d\n", gpio, func, pull, dir, drvstr);
+ }
+
+ cfg = GPIO_CFG(ignore ? 0xff : gpio, func, dir, pull, drvstr);
+#if 1 //TBD
+ res = tlmm_before_sleep_table_set_cfg(gpio, cfg | (output_val << 30));
+ if(res < 0) {
+ printk("Error: Config failed.\n");
+ goto tlmm_before_sleep_table_store_wrong_para;
+ }
+#endif
+
+ goto tlmm_before_sleep_table_store_ok;
+
+tlmm_before_sleep_table_store_wrong_para:
+ printk("Wrong Input.\n");
+ printk("Format: refer to tlmm's format except 'echo gpio_num > xxx' to disable the gpio's setting\n");
+
+tlmm_before_sleep_table_store_ok:
+ return n;
+}
+
+extern int tlmm_before_sleep_dump_info(char* buf);
+static ssize_t tlmm_before_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+#if 1 //TBD
+ p += tlmm_before_sleep_dump_info(buf);
+#endif
+ return p - buf;
+}
+
+static ssize_t tlmm_before_sleep_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support.\n", __func__);
+ return n;
+}
+#endif
+extern int vreg_dump_info(char* buf);
+static ssize_t vreg_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+ p += vreg_dump_info(buf);
+ return p - buf;
+}
+
+//extern void vreg_config(struct vreg *vreg, unsigned on, unsigned mv);
+#if 0
+extern void regulator_config(struct regulator *reg, unsigned on, unsigned mv);
+#endif
+static ssize_t vreg_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support.\n", __func__);
+ return n;
+}
+
+extern int vreg_before_sleep_dump_info(char* buf);
+static ssize_t vreg_before_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char* p = buf;
+ p += vreg_before_sleep_dump_info(buf);
+ return p - buf;
+}
+
+static ssize_t vreg_before_sleep_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support.\n", __func__);
+ return n;
+}
+
+static ssize_t clk_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+#if 0
+ extern int clk_dump_info(char* buf);
+#endif //0
+ char *s = buf;
+
+ // show all enabled clocks
+#if 0
+ //s += sprintf(s, "\nEnabled Clocks:\n");
+ s += clk_dump_info(s);
+#else
+ //Use interface /sys/kernel/debug/clk/enabled_clocks provided by krait instead
+ s += sprintf(s, "cat /sys/kernel/debug/clk/enabled_clocks to show Enabled Clocks\n");
+#endif //0
+
+ return (s - buf);
+}
+
+static ssize_t clk_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support.\n", __func__);
+
+ return -EPERM;
+}
+/* chenyb1 add thermal config for benchmark 20150612 begin*/
+unsigned int thermal_bm_flag = 0;
+static ssize_t thermal_bm_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ printk(KERN_ERR "%s,thermal_bm_flag=%d\n", __func__, thermal_bm_flag);
+
+ return snprintf(buf, 10, "%d\n", thermal_bm_flag);
+}
+
+static ssize_t thermal_bm_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ const char *s = buf;
+
+ thermal_bm_flag = s[0] - '0';
+ sysfs_notify(sysfs_private_kobj, NULL, "thermal_bm");
+ printk(KERN_ERR "%s,thermal_bm_flag=%d\n", __func__, thermal_bm_flag);
+
+ return n;
+}
+/* chenyb1 add thermal config for benchmark 20150612 begin*/
+
+extern unsigned long acpu_clk_get_rate(int cpu);
+extern int wakelock_dump_info(char* buf);
+static ssize_t pm_status_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char *s = buf;
+ unsigned long rate; // khz
+ int cpu;
+
+ // show CPU clocks
+ for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
+ s += sprintf(s, "APPS[%d]:", cpu);
+ if (cpu_online(cpu)) {
+#if 0
+ //acpuclk_get_rate doesn't work because acpuclk_data is no longer available in krait
+ rate = acpuclk_get_rate(cpu); // khz
+ s += sprintf(s, "(%3lu MHz); \n", rate / 1000);
+#else
+ //Call acpu_clk_get_rate added in clock-krait-8974.c
+ rate = acpu_clk_get_rate(cpu); // hz
+ s += sprintf(s, "(%3lu MHz); \n", rate / 1000000);
+#endif
+ } else {
+ s += sprintf(s, "sleep; \n");
+ }
+ }
+
+ s += wakelock_dump_info(s);
+
+ return (s - buf);
+}
+
+static ssize_t pm_status_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support yet.\n", __func__);
+
+ return -EPERM;
+}
+
+static unsigned pm_wakeup_fetched = true;
+static ssize_t pm_wakeup_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char *s = buf;
+
+ if (!pm_wakeup_fetched) {
+ pm_wakeup_fetched = true;
+ s += sprintf(s, "true");
+ } else
+ s += sprintf(s, "false");
+
+ return (s - buf);
+}
+
+static ssize_t pm_wakeup_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ printk(KERN_ERR "%s: no support yet.\n", __func__);
+
+ return -EPERM;
+}
+
+// create a sys interface for power monitor
+#define PM_MONITOR_BUF_LEN 128
+static char pm_monitor_buf[PM_MONITOR_BUF_LEN] = {0};
+static ssize_t pm_monitor_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PM_MONITOR_BUF_LEN, "%s", pm_monitor_buf);
+}
+
+static ssize_t pm_monitor_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ if (n>(PM_MONITOR_BUF_LEN-1) || n<=0)
+ {
+ printk(KERN_ERR "%s: %d\n", __func__, (int)n);
+ return -EPERM;
+ }
+
+ snprintf(pm_monitor_buf, PM_MONITOR_BUF_LEN, "%s", buf);
+ pm_monitor_buf[n] = '\0';
+ printk(KERN_ERR "%s: %s,%d\n", __func__, pm_monitor_buf, (int)n);
+
+ return n;
+}
+
+#ifdef CONFIG_LENOVO_PM_LOG_TLMM//TBD
+private_attr(tlmm_sim);
+private_attr(tlmm_num);
+private_attr(tlmm);
+private_attr(tlmm_before_sleep_table);
+private_attr(tlmm_before_sleep);
+#endif
+private_attr(vreg_before_sleep);
+private_attr(vreg);
+private_attr(clk);
+private_attr(thermal_bm);
+private_attr(pm_status);
+private_attr(pm_wakeup);
+private_attr(pm_monitor);
+
+static struct attribute *g_private_attr[] = {
+#ifdef CONFIG_LENOVO_PM_LOG_TLMM//TBD
+ &tlmm_sim_attr.attr,
+ &tlmm_num_attr.attr,
+ &tlmm_attr.attr,
+ &tlmm_before_sleep_table_attr.attr,
+ &tlmm_before_sleep_attr.attr,
+#endif
+ &vreg_attr.attr,
+ &vreg_before_sleep_attr.attr,
+ &clk_attr.attr,
+ &thermal_bm_attr.attr,
+ &pm_status_attr.attr,
+ &pm_wakeup_attr.attr,
+ &pm_monitor_attr.attr,
+ NULL,
+};
+
+static struct attribute_group private_attr_group = {
+ .attrs = g_private_attr,
+};
+
+#define SLEEP_LOG
+#ifdef SLEEP_LOG
+#define WRITE_SLEEP_LOG
+#define MAX_WAKEUP_IRQ 8
+
+enum {
+ DEBUG_SLEEP_LOG = 1U << 0,
+ DEBUG_WRITE_LOG = 1U << 1,
+ DEBUG_WAKEUP_IRQ = 1U << 2,
+ DEBUG_RPM_SPM_LOG = 1U << 3,
+ DEBUG_RPM_CXO_LOG = 1U << 4,
+ DEBUG_ADSP_CXO_LOG = 1U << 5,
+ DEBUG_MODEM_CXO_LOG = 1U << 6,
+ DEBUG_WCNSS_CXO_LOG = 1U << 7,
+};
+static int debug_mask;// = DEBUG_WRITE_LOG;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+struct sleep_log_t {
+ char time[18];
+ long timesec;
+ unsigned int log;
+ uint32_t maoints[2];
+ int wakeup_irq[MAX_WAKEUP_IRQ];
+ int wakeup_gpio;
+//31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
+//bit1-0=00 :try to sleep; bit 1-0 = 01 : leave from sleep ;bit1-0=10:fail to sleep
+//bit31-bit24 : return value
+};
+
+struct rpm_smem_state_t {
+ uint32_t wakeup_ints[2];
+};
+struct rpm_smem_state_t rpm_smem_state_data;
+
+#define TRY_TO_SLEEP (0)
+#define LEAVE_FORM_SLEEP (1)
+#define FAIL_TO_SLEEP (2)
+
+#define SLEEP_LOG_LENGTH 80
+
+struct sleep_log_t sleep_log_array[SLEEP_LOG_LENGTH];
+int sleep_log_pointer = 0;
+int sleep_log_count = 0;
+int enter_times = 0;
+
+static int irq_wakeup_saved = MAX_WAKEUP_IRQ;
+static int irq_wakeup_irq[MAX_WAKEUP_IRQ];
+static int irq_wakeup_gpio;
+
+char sleep_log_name[60];
+struct file *sleep_log_file = NULL;
+
+#ifdef WRITE_SLEEP_LOG
+static int sleep_log_write(void)
+{
+ char buf[256];
+ char *p, *p0;
+ int i, j, pos;
+ mm_segment_t old_fs;
+ p = buf;
+ p0 = p;
+
+ if (sleep_log_file == NULL)
+ sleep_log_file = filp_open(sleep_log_name, O_RDWR | O_APPEND | O_CREAT,
+ 0644);
+ if (IS_ERR(sleep_log_file)) {
+ printk("error occured while opening file %s, exiting...\n",
+ sleep_log_name);
+ return 0;
+ }
+
+ if (sleep_log_count > 1) {
+ for (i = 0; i < 2; i++) {
+ if (sleep_log_pointer == 0)
+ pos = SLEEP_LOG_LENGTH - 2 + i;
+ else
+ pos = sleep_log_pointer - 2 + i;
+ switch (sleep_log_array[pos].log & 0xF) {
+ case TRY_TO_SLEEP:
+ p += sprintf(p, ">[%ld]%s\n", sleep_log_array[pos].timesec,
+ sleep_log_array[pos].time);
+ break;
+ case LEAVE_FORM_SLEEP:
+ p += sprintf(p, "<[%ld]%s(0x%x,0x%x,",
+ sleep_log_array[pos].timesec,
+ sleep_log_array[pos].time,
+ sleep_log_array[pos].maoints[0],
+ sleep_log_array[pos].maoints[1]);
+ for (j = 0; j < MAX_WAKEUP_IRQ && sleep_log_array[pos].wakeup_irq[j]; j++)
+ p += sprintf(p, " %d", sleep_log_array[pos].wakeup_irq[j]);
+
+ if (sleep_log_array[pos].wakeup_gpio)
+ p += sprintf(p, ", gpio %d", sleep_log_array[pos].wakeup_gpio);
+
+ p += sprintf(p, ")\n");
+ break;
+ case FAIL_TO_SLEEP:
+ p += sprintf(p, "^[%ld]%s(%d)\n", sleep_log_array[pos].timesec,
+ sleep_log_array[pos].time,
+ (char) (sleep_log_array[pos].log >> 24));
+ break;
+ }
+ }
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ vfs_write(sleep_log_file, p0, p - p0,
+ &sleep_log_file->f_pos);
+ set_fs(old_fs);
+
+ if (sleep_log_file != NULL) {
+ filp_close(sleep_log_file, NULL);
+ sleep_log_file = NULL;
+ }
+ return 0;
+}
+#else //WRITE_SLEEP_LOG
+static int sleep_log_write(void)
+{
+ return 0;
+}
+#endif //WRITE_SLEEP_LOG
+
+static int save_irq_wakeup_internal(int irq)
+{
+ int i;
+ int ret;
+
+ ret = 0;
+ if (irq_wakeup_saved < MAX_WAKEUP_IRQ) {
+ for (i = 0; i < irq_wakeup_saved; i++) {
+ if (irq == irq_wakeup_irq[i])
+ break;
+ }
+ if (i == irq_wakeup_saved)
+ ret = irq_wakeup_irq[irq_wakeup_saved++] = irq;
+ }
+ return ret;
+}
+
+int save_irq_wakeup_gpio(int irq, int gpio)
+{
+ struct irq_desc *desc;
+ int ret;
+
+ ret = 0;
+ if (debug_mask & DEBUG_WAKEUP_IRQ) {
+ desc = irq_to_desc(irq);
+ if (desc != NULL) {
+ //if (irqd_is_wakeup_set(&desc->irq_data)) {
+ ret = save_irq_wakeup_internal(irq);
+ if (ret) {
+ if (gpio != 0 && irq_wakeup_gpio == 0) {
+ irq_wakeup_gpio = gpio;
+ irq_wakeup_saved = MAX_WAKEUP_IRQ;
+ }
+#ifdef CONFIG_KALLSYMS
+ printk("%s(), irq=%d, gpio=%d, %s, handler=(%pS)\n", __func__, irq, gpio,
+ desc->action && desc->action->name ? desc->action->name : "",
+ desc->action ? (void *)desc->action->handler : 0);
+#else
+ printk("%s(), irq=%d, gpio=%d, %s, handler=0x%08x\n", __func__, irq, gpio,
+ desc->action && desc->action->name ? desc->action->name : "",
+ desc->action ? (unsigned int)desc->action->handler : 0);
+#endif
+ }
+// }//if (irqd_is_wakeup_set(&desc->irq_data)) {
+ }
+ }
+
+ return ret;
+}
+
+static void clear_irq_wakeup_saved(void)
+{
+ if (debug_mask & DEBUG_WAKEUP_IRQ) {
+ memset(irq_wakeup_irq, 0, sizeof(irq_wakeup_irq));
+ irq_wakeup_gpio = 0;
+ irq_wakeup_saved = 0;
+ }
+}
+
+static void set_irq_wakeup_saved(void)
+{
+ if (debug_mask & DEBUG_WAKEUP_IRQ)
+ irq_wakeup_saved = MAX_WAKEUP_IRQ;
+}
+
+void log_suspend_enter(void)
+{
+ extern void smem_set_reserved(int index, int data);
+ struct timespec ts_;
+ struct rtc_time tm_;
+
+ //Turn on/off the share memory flag to inform RPM to record spm logs
+ //smem_set_reserved(6, debug_mask & DEBUG_WAKEUP_IRQ ? 1 : 0);
+// smem_set_reserved(6, debug_mask);
+
+ if (debug_mask & DEBUG_SLEEP_LOG) {
+ printk("%s(), APPS try to ENTER sleep mode>>>\n", __func__);
+
+ getnstimeofday(&ts_);
+ rtc_time_to_tm(ts_.tv_sec + 8 * 3600, &tm_);
+
+ sprintf(sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].time,
+ "%d-%02d-%02d %02d:%02d:%02d", tm_.tm_year + 1900, tm_.tm_mon + 1,
+ tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec);
+
+ if (strlen(sleep_log_name) < 1) {
+ sprintf(sleep_log_name,
+ "/data/local/log/aplog/sleeplog%d%02d%02d_%02d%02d%02d.txt",
+ tm_.tm_year + 1900, tm_.tm_mon + 1, tm_.tm_mday, tm_.tm_hour,
+ tm_.tm_min, tm_.tm_sec);
+ printk("%s(), sleep_log_name = %s \n", __func__, sleep_log_name);
+ }
+
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].timesec = ts_.tv_sec;
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].log = TRY_TO_SLEEP;
+ sleep_log_pointer++;
+ sleep_log_count++;
+ if (sleep_log_pointer == SLEEP_LOG_LENGTH)
+ sleep_log_pointer = 0;
+ }
+
+ clear_irq_wakeup_saved();
+ pm_wakeup_fetched = false;
+}
+
+void log_suspend_exit(int error)
+{
+#if 0
+ extern int smem_get_reserved(int index);
+#else
+ extern void msm_rpmstats_get_reverved(u32 reserved[][4]);
+ u32 reserved[4][4];
+#endif
+ struct timespec ts_;
+ struct rtc_time tm_;
+ uint32_t smem_value;
+ int i;
+
+ if (debug_mask & DEBUG_SLEEP_LOG) {
+ getnstimeofday(&ts_);
+ rtc_time_to_tm(ts_.tv_sec + 8 * 3600, &tm_);
+ sprintf(sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].time,
+ "%d-%02d-%02d %02d:%02d:%02d", tm_.tm_year + 1900, tm_.tm_mon + 1,
+ tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec);
+
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].timesec = ts_.tv_sec;
+
+ if (error == 0) {
+#if 0
+ rpm_smem_state_data.wakeup_ints[0] = smem_get_reserved(0);
+ rpm_smem_state_data.wakeup_ints[1] = smem_get_reserved(1);
+#elif 0
+ if (debug_mask & DEBUG_RPM_SPM_LOG) {
+ for(i = 0; i <= 5; i++) {
+ smem_value = ((uint32_t)smem_get_reserved(i)) & 0xffff;
+ if(smem_value > 0)
+ printk("rpm: %s[%d] = %d\n", "spm_active" , i, smem_value);
+ }
+ }
+ if (debug_mask & DEBUG_RPM_CXO_LOG) {
+ for(i = 0; i <= 5; i++) {
+ smem_value = ((uint32_t)smem_get_reserved(i)) >> 16;
+ if(smem_value > 0)
+ printk("rpm: %s[%d] = %d\n", "cxo_voter" , i, smem_value);
+ }
+ }
+#else
+ printk("%s, debug_mask=%x\n", __func__, debug_mask);
+ if (debug_mask & (DEBUG_RPM_SPM_LOG | DEBUG_RPM_CXO_LOG)) {
+ memset(reserved, 0, sizeof(reserved));
+ msm_rpmstats_get_reverved(reserved);
+#if 1
+ for(i = 0; i < 3; i++)
+ printk("reserved[0][%d]=0x%08x\n", i, reserved[0][i]);
+ for(i = 0; i < 3; i++)
+ printk("reserved[1][%d]=0x%08x\n", i, reserved[1][i]);
+#endif
+ }
+
+ if (debug_mask & DEBUG_RPM_SPM_LOG) {
+ for(i = 0; i <= 5; i++) {
+ smem_value = (reserved[1][i/2] >> (16 * (i % 2))) & 0xffff;
+ if(smem_value > 0)
+ printk("rpm: %s[%d] = %d\n", "spm_active" , i, smem_value);
+ }
+ }
+ if (debug_mask & DEBUG_RPM_CXO_LOG) {
+ for(i = 0; i <= 5; i++) {
+ smem_value = (reserved[0][i/2] >> (16 * (i % 2))) & 0xffff;
+ if(smem_value > 0)
+ printk("rpm: %s[%d] = %d\n", "cxo_voter" , i, smem_value);
+ }
+ }
+#endif
+
+ printk("%s(), APPS Exit from sleep<<<: wakeup ints=0x%x, 0x%x\n", __func__ ,
+ rpm_smem_state_data.wakeup_ints[0],
+ rpm_smem_state_data.wakeup_ints[1]);
+
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].log =
+ LEAVE_FORM_SLEEP;
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].maoints[0] =
+ rpm_smem_state_data.wakeup_ints[0];
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].maoints[1] =
+ rpm_smem_state_data.wakeup_ints[1];
+ for (i = 0; i < (irq_wakeup_gpio == 0 ? irq_wakeup_saved : 1); i++)
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].wakeup_irq[i] =
+ irq_wakeup_irq[i];
+ for (; i < MAX_WAKEUP_IRQ; i++)
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].wakeup_irq[i] = 0;
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].wakeup_gpio =
+ irq_wakeup_gpio;
+ } else {
+ printk("%s(), APPS FAIL to enter sleep^^^\n", __func__);
+
+ sleep_log_array[sleep_log_pointer % SLEEP_LOG_LENGTH].log =
+ FAIL_TO_SLEEP | (error << 24);
+ }
+
+ sleep_log_pointer++;
+ sleep_log_count++;
+
+ if (sleep_log_pointer == SLEEP_LOG_LENGTH)
+ sleep_log_pointer = 0;
+
+ if (debug_mask & DEBUG_WRITE_LOG) {
+ enter_times++;
+ if (enter_times < 5000)
+ sleep_log_write();
+ }
+ }
+
+ set_irq_wakeup_saved();
+}
+#else //SLEEP_LOG
+void log_suspend_enter(void)
+{
+ clear_irq_wakeup_saved();
+ pm_wakeup_fetched = false;
+}
+
+void log_suspend_exit(int error)
+{
+ set_irq_wakeup_saved();
+}
+#endif //SLEEP_LOG
+
+static const struct of_device_id sysfs_private_tlmm_dt_match[] = {
+ { .compatible = "qcom,msmtitanium-pinctrl", },
+ { },
+};
+
+static int sysfs_private_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device_node *node = pdev->dev.of_node;
+ int size = 0;
+ int ret = 0;
+ struct regulator *vdd_l16;
+ u32 voltage_low, voltage_high;
+ //int i = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot find IO resource\n");
+ return -ENOENT;
+ }
+/*
+* Request same resource could cause ioremap failed and
+* return -EBUSY.Therefore we remove it.
+*/
+/*
+ tlmm_reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tlmm_reg_base))
+ return PTR_ERR(tlmm_reg_base);
+*/
+ of_get_property(node, "lenovo,tz_gpio", &size);
+ //printk("%s(), %d, size=%d\n", __func__, __LINE__, size);
+ if (size) {
+ tz_pin_num = size / sizeof(u32);
+ tz_config = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ ret = of_property_read_u32_array(node,
+ "lenovo,tz_gpio", tz_config,
+ tz_pin_num);
+/*
+ for(i = 0; i < tz_pin_num; i++)
+ {
+ pr_debug("%s(), %d, tz_config[%d]=%d\n", __func__, __LINE__, i, tz_config[i]);
+ }
+*/
+ }
+ printk("%s(), %d, TLMM_BASE=%lx\n", __func__, __LINE__, (unsigned long int)(void *)tlmm_reg_base);
+
+ // enable l16
+ if (of_find_property(node, "vdd-supply", NULL)) {
+ vdd_l16 = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(vdd_l16))
+ return PTR_ERR(vdd_l16);
+ }
+
+ ret = of_property_read_u32(node, "vdd-low-microvolt",
+ &voltage_low);
+ if (ret) {
+ dev_err(&pdev->dev, "no vdd-low-microvolt property set\n");
+ return ret;
+ }
+ ret = of_property_read_u32(node, "vdd-low-microvolt",
+ &voltage_high);
+ if (ret) {
+ dev_err(&pdev->dev, "no vdd-low-microvolt property set\n");
+ return ret;
+ }
+ if (regulator_count_voltages(vdd_l16) <= 0)
+ return 0;
+
+ printk("%s(), %d, voltage_low=%u, voltage_high=%u\n", __func__, __LINE__, voltage_low, voltage_high);
+
+ regulator_set_voltage(vdd_l16, voltage_low, voltage_high);
+
+ ret = regulator_enable(vdd_l16);
+ pr_err("enable l16 regulator rc=%d\n", ret);
+ if (ret) {
+ pr_err("failed to enable l16 regulator rc=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id msmtitanium_pinctrl_of_match[] = {
+ { .compatible = "qcom,sysfs_private", },
+ { },
+};
+
+static struct platform_driver sysfs_private_drv = {
+ .probe = sysfs_private_probe,
+ .driver = {
+ .name = "sysfs_private",
+ .owner = THIS_MODULE,
+ .of_match_table = msmtitanium_pinctrl_of_match,
+ },
+};
+
+
+MODULE_DEVICE_TABLE(of, msm_tlmm_dt_match);
+
+
+
+static int __init sysfs_private_init(void)
+{
+ int result;
+
+ printk("%s(), %d\n", __func__, __LINE__);
+
+ sysfs_private_kobj = kobject_create_and_add("private", NULL);
+ if (!sysfs_private_kobj)
+ return -ENOMEM;
+
+ result = sysfs_create_group(sysfs_private_kobj, &private_attr_group);
+ printk("%s(), %d, result=%d\n", __func__, __LINE__, result);
+
+#ifdef SLEEP_LOG
+ strcpy (sleep_log_name, "");
+ sleep_log_pointer = 0;
+ sleep_log_count = 0;
+ enter_times = 0;
+#endif
+
+ platform_driver_register(&sysfs_private_drv);
+ //tlmm_reg_base = ioremap((resource_size_t )0x1000000, (unsigned long)0x300000);
+
+ return 0;//platform_driver_register(&sysfs_private_drv);
+}
+
+static void __exit sysfs_private_exit(void)
+{
+ printk("%s(), %d\n", __func__, __LINE__);
+ sysfs_remove_group(sysfs_private_kobj, &private_attr_group);
+
+ kobject_put(sysfs_private_kobj);
+
+ platform_driver_unregister(&sysfs_private_drv);
+}
+
+module_init(sysfs_private_init);
+module_exit(sysfs_private_exit);