/* 2009-08-18: File added and changed by Sony Corporation */
/*
 *  Copyright 2009 Sony Corporation.
 *
 *  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;  version 2 of the  License.
 *
 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  You should have received a copy of the  GNU General Public License along
 *  with this program; if not, write  to the Free Software Foundation, Inc.,
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/arch/pwc.h>
#include "chargerif.h"
#include "controller.h"
#include "internal.h"
#include "suspend.h"

controller_status_t controller_status;

static int     navu2pm_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
static ssize_t navu2pm_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos);
static int     acc_wake_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
static ssize_t acc_wake_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos);


#ifdef CONFIG_PGPF_NAVU2_PM_APPTHERM
static int     faketherm_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
static ssize_t faketherm_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos);
static int     fakehitemp_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
static ssize_t fakehitemp_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos);

static int     fakehitemp;
#endif /* CONFIG_PGPF_NAVU2_PM_APPTHERM */

navu2pm_status_t navu2pm_proc_register(void)
{
	struct proc_dir_entry *entry;
	struct proc_dir_entry *acc_wake_entry;

#ifdef CONFIG_PGPF_NAVU2_PM_APPTHERM
	struct proc_dir_entry *fake_therm_entry;
	struct proc_dir_entry *fake_hitemp_entry;
#endif /* CONFIG_PGPF_NAVU2_PM_APPTHERM */

	/* proc for suspend and battery status */
	entry = create_proc_read_entry("navu2pm", S_IWUSR | S_IRUGO, NULL,
								   navu2pm_read_proc, 0);
	if(NULL == entry){
		return NAVU2PM_ERR_OTHER;
	}
	entry->write_proc = (write_proc_t *)navu2pm_write_proc;

	/* proc for acc_wakeup setting */
	acc_wake_entry = create_proc_read_entry("navu2pm_acc", S_IWUSR | S_IRUGO, NULL,
								   acc_wake_read_proc, 0);
	if(NULL == acc_wake_entry){
		return NAVU2PM_ERR_OTHER;
	}
	acc_wake_entry->write_proc = (write_proc_t *)acc_wake_write_proc;

#ifdef CONFIG_PGPF_NAVU2_PM_APPTHERM
	/* for debug */
	fake_therm_entry = create_proc_read_entry("faketherm", S_IWUSR | S_IRUGO, NULL,
								   faketherm_read_proc, 0);
	if(NULL == fake_therm_entry){
		return NAVU2PM_ERR_OTHER;
	}
	fake_therm_entry->write_proc = (write_proc_t *)faketherm_write_proc;

	fake_hitemp_entry = create_proc_read_entry("fakehitemp", S_IWUSR | S_IRUGO, NULL,
								   fakehitemp_read_proc, 0);
	if(NULL == fake_hitemp_entry){
		return NAVU2PM_ERR_OTHER;
	}
	fake_hitemp_entry->write_proc = (write_proc_t *)fakehitemp_write_proc;
	
#endif /* CONFIG_PGPF_NAVU2_PM_APPTHERM */

	return NAVU2PM_SUCCESS;
}

static int navu2pm_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	int len; 

	controller_get_controller_status(&controller_status);

	len = snprintf(page, count, "%d/0x%x\t%d/0x%x\t0x%x\n", 
				  controller_status.bc,
				  controller_status.bc_hex,
				  controller_status.bv,
				  controller_status.bv_hex,
				  controller_status.bt_hex);

	*eof = 1;

	return len;
}

static ssize_t navu2pm_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    int ret = 0;
    char *buf;
    char *tok;
    char *s;
    char *str;
    char *whitespace = " \t\r\n";

    if (0 == count){
        return ret;
    }

    buf = kmalloc(count + 1, GFP_KERNEL);
    if (buf == NULL) {
        ret = -ENOMEM;
        goto exit_2;
    }

    if (copy_from_user(buf, buffer, count) != 0) {
        ret = -EFAULT;
        goto exit_1;
    }

    buf[count] = '\0';
    s = buf + strspn(buf, whitespace);
    tok = strsep(&s, whitespace);
	if(NULL == tok){
		ret = -EFAULT;
		goto exit_1;
	}

    str = "suspend";
    if (strnicmp(tok, str, strlen(str) + 1) == 0) {
        DPRINT("Suspend\n");

		controller_request_suspend();

        goto exit_1;
    }

	ret = -EINVAL;

  exit_1:    
	kfree(buf);

  exit_2:

    if (ret == 0) {
        return count;
    }

    return ret;
}

static int acc_wake_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	int len;

	len = snprintf(page, count, "%d\n", (int)controller_get_acc_wake());

	*eof = 1;

	return len;
}

static ssize_t acc_wake_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    int ret = 0;
    char *buf;
    char *tok;
    char *s;
    char *whitespace = " \t\r\n";
	unsigned long val;

    if (0 == count){
        return ret;
    }

    buf = kmalloc(count + 1, GFP_KERNEL);
    if (buf == NULL) {
        ret = -ENOMEM;
        goto exit_2;
    }

    if (copy_from_user(buf, buffer, count) != 0) {
        ret = -EFAULT;
        goto exit_1;
    }

    buf[count] = '\0';
    s = buf + strspn(buf, whitespace);
    tok = strsep(&s, whitespace);
	if(NULL == tok){
		ret = -EFAULT;
		goto exit_1;
	}

	val = simple_strtol(tok, NULL, 0);
	controller_set_acc_wake((int)val);

	ret = -EINVAL;

  exit_1:    
	kfree(buf);

  exit_2:

    if (ret == 0) {
        return count;
    }

    return ret;
}

#ifdef CONFIG_PGPF_NAVU2_PM_APPTHERM

static int faketherm_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	int len;

	len = sprintf(page, " faketherm \n");
	*eof = 1;

	return len;
}

static ssize_t faketherm_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    int ret = 0;
    char *buf;
    char *tok;
    char *s;
    char *str;
    char *whitespace = " \t\r\n";
	unsigned long val;

    if (0 == count){
        return ret;
    }

    buf = kmalloc(count + 1, GFP_KERNEL);
    if (buf == NULL) {
        ret = -ENOMEM;
        goto exit_2;
    }

    if (copy_from_user(buf, buffer, count) != 0) {
        ret = -EFAULT;
        goto exit_1;
    }

    buf[count] = '\0';
    s = buf + strspn(buf, whitespace);
    tok = strsep(&s, whitespace);

	str = "stop";
    if (strnicmp(tok, str, strlen(str) + 1) == 0) {
        DPRINT("Set ICHRG 0mA\n");

		stop_fake_therm();

        goto exit_1;
    }

	val = simple_strtol(tok, NULL, 0);
	start_fake_therm((unsigned short)val);

	ret = -EINVAL;

  exit_1:    
	kfree(buf);

  exit_2:

    if (ret == 0) {
        return count;
    }

    return ret;
}

static int fakehitemp_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	int len;

	len = snprintf(page, count, "%d\n", fakehitemp);

	*eof = 1;

	return len;
}

static ssize_t fakehitemp_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    int ret = 0;
    char *buf;
    char *tok;
    char *s;
    char *whitespace = " \t\r\n";
	unsigned long val;

    if (0 == count){
        return ret;
    }

    buf = kmalloc(count + 1, GFP_KERNEL);
    if (buf == NULL) {
        ret = -ENOMEM;
        goto exit_2;
    }

    if (copy_from_user(buf, buffer, count) != 0) {
        ret = -EFAULT;
        goto exit_1;
    }

    buf[count] = '\0';
    s = buf + strspn(buf, whitespace);
    tok = strsep(&s, whitespace);
	if(NULL == tok){
		ret = -EFAULT;
		goto exit_1;
	}

	val = simple_strtol(tok, NULL, 0);
	fakehitemp = (int)val;

	if(fakehitemp){
		pwc_write(PWC_GPPUPD1, 0x04, 0x0C);
	}else{
		pwc_write(PWC_GPPUPD1, 0x08, 0x0C);
	}

	ret = -EINVAL;

  exit_1:    
	kfree(buf);

  exit_2:

    if (ret == 0) {
        return count;
    }

    return ret;
}

#endif /* CONFIG_PGPF_NAVU2_PM_APPTHERM */
