[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1374676030-4534-1-git-send-email-czoborbalint@gmail.com>
Date: Wed, 24 Jul 2013 16:27:10 +0200
From: Balint Czobor <czoborbalint@...il.com>
To: Anton Vorontsov <anton@...msg.org>,
David Woodhouse <dwmw2@...radead.org>
Cc: linux-kernel@...r.kernel.org,
Balint Czobor <czoborbalint@...il.com>
Subject: [PATCH 2/2] drivers: power: Add support for BATTERY_ARIESVE
Add initial support for the battery in Samsung ARIESVE.
Signed-off-by: Balint Czobor <czoborbalint@...il.com>
---
arch/arm/mach-msm/include/mach/msm_battery.h | 31 +
arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 376 ++++
drivers/power/Kconfig | 14 +
drivers/power/Makefile | 1 +
drivers/power/ariesve_battery.c | 2710 ++++++++++++++++++++++++
drivers/power/fuelgauge_max17043.c | 434 ++++
drivers/power/power_supply_sysfs.c | 19 +-
include/linux/earlysuspend.h | 56 +
include/linux/leds-pmic8058.h | 40 +
include/linux/mfd/pm8xxx/batt-alarm.h | 201 ++
include/linux/mfd/pm8xxx/gpio.h | 162 ++
include/linux/mfd/pm8xxx/misc.h | 284 +++
include/linux/mfd/pm8xxx/mpp.h | 263 +++
include/linux/mfd/pm8xxx/nfc.h | 79 +
include/linux/mfd/pm8xxx/tm.h | 42 +
include/linux/mfd/pm8xxx/upl.h | 65 +
include/linux/mfd/pm8xxx/vibrator.h | 39 +
include/linux/mfd/pmic8058.h | 137 ++
include/linux/pmic8058-othc.h | 146 ++
include/linux/pmic8058-pwm.h | 148 ++
include/linux/pmic8058-xoadc.h | 121 ++
include/linux/power_supply.h | 13 +-
include/linux/regulator/pm8058-xo.h | 31 +
include/linux/regulator/pmic8058-regulator.h | 89 +
include/linux/wakelock.h | 90 +
25 files changed, 5588 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/mach-msm/include/mach/msm_battery.h
create mode 100644 arch/arm/mach-msm/include/mach/msm_rpcrouter.h
create mode 100644 drivers/power/ariesve_battery.c
create mode 100644 drivers/power/fuelgauge_max17043.c
create mode 100644 include/linux/earlysuspend.h
create mode 100644 include/linux/leds-pmic8058.h
create mode 100644 include/linux/mfd/pm8xxx/batt-alarm.h
create mode 100644 include/linux/mfd/pm8xxx/gpio.h
create mode 100644 include/linux/mfd/pm8xxx/misc.h
create mode 100644 include/linux/mfd/pm8xxx/mpp.h
create mode 100644 include/linux/mfd/pm8xxx/nfc.h
create mode 100644 include/linux/mfd/pm8xxx/tm.h
create mode 100644 include/linux/mfd/pm8xxx/upl.h
create mode 100644 include/linux/mfd/pm8xxx/vibrator.h
create mode 100644 include/linux/mfd/pmic8058.h
create mode 100644 include/linux/pmic8058-othc.h
create mode 100644 include/linux/pmic8058-pwm.h
create mode 100644 include/linux/pmic8058-xoadc.h
create mode 100644 include/linux/regulator/pm8058-xo.h
create mode 100644 include/linux/regulator/pmic8058-regulator.h
create mode 100644 include/linux/wakelock.h
diff --git a/arch/arm/mach-msm/include/mach/msm_battery.h b/arch/arm/mach-msm/include/mach/msm_battery.h
new file mode 100644
index 0000000..dfa8097
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_battery.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef __MSM_BATTERY_H__
+#define __MSM_BATTERY_H__
+
+#define NO_CHG 0x00000000
+#define AC_CHG 0x00000001
+#define USB_CHG 0x00000002
+
+struct msm_psy_batt_pdata {
+ u32 voltage_max_design;
+ u32 voltage_min_design;
+ u32 voltage_fail_safe;
+ u32 avail_chg_sources;
+ u32 batt_technology;
+ u32 (*calculate_capacity)(u32 voltage);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
new file mode 100644
index 0000000..28841a9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
@@ -0,0 +1,376 @@
+/** include/asm-arm/arch-msm/msm_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@...roid.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM__ARCH_MSM_RPCROUTER_H
+#define __ASM__ARCH_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+
+/* RPC API version structure
+ * Version bit 31 : 1->hashkey versioning,
+ * 0->major-minor (backward compatible) versioning
+ * hashkey versioning:
+ * Version bits 31-0 hashkey
+ * major-minor (backward compatible) versioning
+ * Version bits 30-28 reserved (no match)
+ * Version bits 27-16 major (must match)
+ * Version bits 15-0 minor (greater or equal)
+ */
+#define RPC_VERSION_MODE_MASK 0x80000000
+#define RPC_VERSION_MAJOR_MASK 0x0fff0000
+#define RPC_VERSION_MINOR_MASK 0x0000ffff
+
+/* callback ID for NULL callback function is -1 */
+#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff
+
+struct msm_rpc_endpoint;
+
+struct rpcsvr_platform_device
+{
+ struct platform_device base;
+ uint32_t prog;
+ uint32_t vers;
+};
+
+#define RPC_DATA_IN 0
+/*
+ * Structures for sending / receiving direct RPC requests
+ * XXX: Any cred/verif lengths > 0 not supported
+ */
+
+struct rpc_request_hdr
+{
+ uint32_t xid;
+ uint32_t type; /* 0 */
+ uint32_t rpc_vers; /* 2 */
+ uint32_t prog;
+ uint32_t vers;
+ uint32_t procedure;
+ uint32_t cred_flavor;
+ uint32_t cred_length;
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+};
+
+typedef struct
+{
+ uint32_t low;
+ uint32_t high;
+} rpc_reply_progmismatch_data;
+
+typedef struct
+{
+} rpc_denied_reply_hdr;
+
+typedef struct
+{
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+ uint32_t accept_stat;
+#define RPC_ACCEPTSTAT_SUCCESS 0
+#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1
+#define RPC_ACCEPTSTAT_PROG_MISMATCH 2
+#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3
+#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4
+#define RPC_ACCEPTSTAT_SYSTEM_ERR 5
+#define RPC_ACCEPTSTAT_PROG_LOCKED 6
+ /*
+ * Following data is dependant on accept_stat
+ * If ACCEPTSTAT == PROG_MISMATCH then there is a
+ * 'rpc_reply_progmismatch_data' structure following the header.
+ * Otherwise the data is procedure specific
+ */
+} rpc_accepted_reply_hdr;
+
+struct rpc_reply_hdr
+{
+ uint32_t xid;
+ uint32_t type;
+ uint32_t reply_stat;
+#define RPCMSG_REPLYSTAT_ACCEPTED 0
+#define RPCMSG_REPLYSTAT_DENIED 1
+ union {
+ rpc_accepted_reply_hdr acc_hdr;
+ rpc_denied_reply_hdr dny_hdr;
+ } data;
+};
+
+struct rpc_board_dev {
+ uint32_t prog;
+ struct platform_device pdev;
+};
+
+/* flags for msm_rpc_connect() */
+#define MSM_RPC_UNINTERRUPTIBLE 0x0001
+
+/* use IS_ERR() to check for failure */
+struct msm_rpc_endpoint *msm_rpc_open(void);
+/* Connect with the specified server version */
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags);
+/* Connect with a compatible server version */
+struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
+ uint32_t vers, unsigned flags);
+/* check if server version can handle client requested version */
+int msm_rpc_is_compatible_version(uint32_t server_version,
+ uint32_t client_version);
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept);
+int msm_rpc_write(struct msm_rpc_endpoint *ept,
+ void *data, int len);
+int msm_rpc_read(struct msm_rpc_endpoint *ept,
+ void **data, unsigned len, long timeout);
+void msm_rpc_read_wakeup(struct msm_rpc_endpoint *ept);
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr,
+ uint32_t prog, uint32_t vers, uint32_t proc);
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+
+int msm_rpc_add_board_dev(struct rpc_board_dev *board_dev, int num);
+
+int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept);
+
+int msm_rpc_get_curr_pkt_size(struct msm_rpc_endpoint *ept);
+/* simple blocking rpc call
+ *
+ * request is mandatory and must have a rpc_request_hdr
+ * at the start. The header will be filled out for you.
+ *
+ * reply provides a buffer for replies of reply_max_size
+ */
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ void *reply, int reply_max_size,
+ long timeout);
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ long timeout);
+
+struct msm_rpc_xdr {
+ void *in_buf;
+ uint32_t in_size;
+ uint32_t in_index;
+ wait_queue_head_t in_buf_wait_q;
+
+ void *out_buf;
+ uint32_t out_size;
+ uint32_t out_index;
+ struct mutex out_lock;
+
+ struct msm_rpc_endpoint *ept;
+};
+
+int xdr_send_int8(struct msm_rpc_xdr *xdr, const int8_t *value);
+int xdr_send_uint8(struct msm_rpc_xdr *xdr, const uint8_t *value);
+int xdr_send_int16(struct msm_rpc_xdr *xdr, const int16_t *value);
+int xdr_send_uint16(struct msm_rpc_xdr *xdr, const uint16_t *value);
+int xdr_send_int32(struct msm_rpc_xdr *xdr, const int32_t *value);
+int xdr_send_uint32(struct msm_rpc_xdr *xdr, const uint32_t *value);
+int xdr_send_bytes(struct msm_rpc_xdr *xdr, const void **data, uint32_t *size);
+
+int xdr_recv_int8(struct msm_rpc_xdr *xdr, int8_t *value);
+int xdr_recv_uint8(struct msm_rpc_xdr *xdr, uint8_t *value);
+int xdr_recv_int16(struct msm_rpc_xdr *xdr, int16_t *value);
+int xdr_recv_uint16(struct msm_rpc_xdr *xdr, uint16_t *value);
+int xdr_recv_int32(struct msm_rpc_xdr *xdr, int32_t *value);
+int xdr_recv_uint32(struct msm_rpc_xdr *xdr, uint32_t *value);
+int xdr_recv_bytes(struct msm_rpc_xdr *xdr, void **data, uint32_t *size);
+
+struct msm_rpc_server
+{
+ struct list_head list;
+ uint32_t flags;
+
+ uint32_t prog;
+ uint32_t vers;
+
+ struct mutex cb_req_lock;
+
+ struct msm_rpc_endpoint *cb_ept;
+
+ struct msm_rpc_xdr cb_xdr;
+
+ uint32_t version;
+
+ int (*rpc_call)(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len);
+
+ int (*rpc_call2)(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req,
+ struct msm_rpc_xdr *xdr);
+};
+
+int msm_rpc_create_server(struct msm_rpc_server *server);
+int msm_rpc_create_server2(struct msm_rpc_server *server);
+
+#define MSM_RPC_MSGSIZE_MAX 8192
+
+struct msm_rpc_client;
+
+struct msm_rpc_client {
+ struct task_struct *read_thread;
+ struct task_struct *cb_thread;
+
+ struct msm_rpc_endpoint *ept;
+ wait_queue_head_t reply_wait;
+
+ uint32_t prog, ver;
+
+ void *buf;
+
+ struct msm_rpc_xdr xdr;
+ struct msm_rpc_xdr cb_xdr;
+
+ uint32_t version;
+
+ int (*cb_func)(struct msm_rpc_client *, void *, int);
+ int (*cb_func2)(struct msm_rpc_client *, struct rpc_request_hdr *req,
+ struct msm_rpc_xdr *);
+ void *cb_buf;
+ int cb_size;
+
+ struct list_head cb_item_list;
+ struct mutex cb_item_list_lock;
+
+ wait_queue_head_t cb_wait;
+ int cb_avail;
+
+ atomic_t next_cb_id;
+ spinlock_t cb_list_lock;
+ struct list_head cb_list;
+
+ uint32_t exit_flag;
+ struct completion complete;
+ struct completion cb_complete;
+
+ struct mutex req_lock;
+
+ void (*cb_restart_teardown)(struct msm_rpc_client *client);
+ void (*cb_restart_setup)(struct msm_rpc_client *client);
+ int in_reset;
+};
+
+struct msm_rpc_client_info {
+ uint32_t pid;
+ uint32_t cid;
+ uint32_t prog;
+ uint32_t vers;
+};
+
+
+int msm_rpc_client_in_reset(struct msm_rpc_client *client);
+
+struct msm_rpc_client *msm_rpc_register_client(
+ const char *name,
+ uint32_t prog, uint32_t ver,
+ uint32_t create_cb_thread,
+ int (*cb_func)(struct msm_rpc_client *, void *, int));
+
+struct msm_rpc_client *msm_rpc_register_client2(
+ const char *name,
+ uint32_t prog, uint32_t ver,
+ uint32_t create_cb_thread,
+ int (*cb_func)(struct msm_rpc_client *, struct rpc_request_hdr *req,
+ struct msm_rpc_xdr *xdr));
+
+int msm_rpc_unregister_client(struct msm_rpc_client *client);
+
+int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
+ int (*arg_func)(struct msm_rpc_client *,
+ void *, void *), void *arg_data,
+ int (*result_func)(struct msm_rpc_client *,
+ void *, void *), void *result_data,
+ long timeout);
+
+int msm_rpc_client_req2(struct msm_rpc_client *client, uint32_t proc,
+ int (*arg_func)(struct msm_rpc_client *,
+ struct msm_rpc_xdr *, void *),
+ void *arg_data,
+ int (*result_func)(struct msm_rpc_client *,
+ struct msm_rpc_xdr *, void *),
+ void *result_data,
+ long timeout);
+
+int msm_rpc_register_reset_callbacks(
+ struct msm_rpc_client *client,
+ void (*teardown)(struct msm_rpc_client *client),
+ void (*setup)(struct msm_rpc_client *client)
+ );
+
+void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
+ uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size);
+
+void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server,
+ uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server,
+ uint32_t size);
+
+int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id);
+
+void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+int msm_rpc_server_cb_req(struct msm_rpc_server *server,
+ struct msm_rpc_client_info *clnt_info,
+ uint32_t cb_proc,
+ int (*arg_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *arg_data,
+ int (*ret_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *ret_data, long timeout);
+
+int msm_rpc_server_cb_req2(struct msm_rpc_server *server,
+ struct msm_rpc_client_info *clnt_info,
+ uint32_t cb_proc,
+ int (*arg_func)(struct msm_rpc_server *server,
+ struct msm_rpc_xdr *xdr, void *data),
+ void *arg_data,
+ int (*ret_func)(struct msm_rpc_server *server,
+ struct msm_rpc_xdr *xdr, void *data),
+ void *ret_data, long timeout);
+
+void msm_rpc_server_get_requesting_client(
+ struct msm_rpc_client_info *clnt_info);
+
+int xdr_send_pointer(struct msm_rpc_xdr *xdr, void **obj,
+ uint32_t obj_size, void *xdr_op);
+
+int xdr_recv_pointer(struct msm_rpc_xdr *xdr, void **obj,
+ uint32_t obj_size, void *xdr_op);
+
+int xdr_send_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+ uint32_t maxsize, uint32_t elm_size, void *xdr_op);
+
+int xdr_recv_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+ uint32_t maxsize, uint32_t elm_size, void *xdr_op);
+
+int xdr_recv_req(struct msm_rpc_xdr *xdr, struct rpc_request_hdr *req);
+int xdr_recv_reply(struct msm_rpc_xdr *xdr, struct rpc_reply_hdr *reply);
+int xdr_start_request(struct msm_rpc_xdr *xdr, uint32_t prog,
+ uint32_t ver, uint32_t proc);
+int xdr_start_accepted_reply(struct msm_rpc_xdr *xdr, uint32_t accept_status);
+int xdr_send_msg(struct msm_rpc_xdr *xdr);
+
+#endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7b8979c..847a77e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -75,6 +75,12 @@ config BATTERY_88PM860X
help
Say Y here to enable battery monitor for Marvell 88PM860x chip.
+config BATTERY_ARIESVE
+ tristate "Ariesve battery driver"
+ depends on MACH_ARIESVE
+ help
+ Say Y to enable support for the battery in Samsung ARIESVE.
+
config BATTERY_DS2760
tristate "DS2760 battery driver (HP iPAQ & others)"
depends on W1 && W1_SLAVE_DS2760
@@ -362,6 +368,14 @@ config BATTERY_GOLDFISH
Say Y to enable support for the battery and AC power in the
Goldfish emulator.
+config MAX17043_FUEL_GAUGE
+ tristate "Maxim MAX17043 Fuel Gauge"
+ depends on I2C
+ help
+ MAX17043 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17043 is configured
+ to operate with a single lithium cell.
+
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 653bf6c..9ced370 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_TEST_POWER) += test_power.o
obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
+obj-$(CONFIG_BATTERY_ARIESVE) += ariesve_battery.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
diff --git a/drivers/power/ariesve_battery.c b/drivers/power/ariesve_battery.c
new file mode 100644
index 0000000..3dc03fd
--- /dev/null
+++ b/drivers/power/ariesve_battery.c
@@ -0,0 +1,2710 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/*
+ * this needs to be before <linux/kernel.h> is loaded,
+ * and <linux/sched.h> loads <linux/kernel.h>
+ */
+
+//#define DEBUG 1
+#include <linux/device.h>
+
+#define MAX17043_FUEL_GAUGE // Support low battery alert
+
+// For LPM mode
+extern int charging_boot;
+
+/* ***** Test Features ***** */
+
+//#define __BATT_TEST_DEVICE__
+//#define __AUTO_TEMP_TEST__
+//#define __FULL_CHARGE_TEST__
+
+
+#include <linux/earlysuspend.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <asm/atomic.h>
+
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_battery.h>
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/wakelock.h>
+
+#ifdef CONFIG_WIRELESS_CHARGING
+#define IRQ_WC_DETECT PM8058_GPIO_IRQ(PMIC8058_IRQ_BASE, (PM8058_GPIO(35)))
+#define GPIO_WC_DETECT PM8058_GPIO_PM_TO_SYS(PM8058_GPIO(35))
+#endif
+
+static struct wake_lock vbus_wake_lock;
+
+
+#ifdef DEBUG
+#undef pr_debug
+#define pr_debug pr_info
+#endif
+
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include "fuelgauge_max17043.c"
+#endif
+
+#define BATTERY_RPC_PROG 0x30000089
+#define BATTERY_RPC_VER_1_1 0x00010001
+#define BATTERY_RPC_VER_2_1 0x00020001
+#define BATTERY_RPC_VER_4_1 0x00040001
+#define BATTERY_RPC_VER_5_1 0x00050001
+
+#define BATTERY_RPC_CB_PROG (BATTERY_RPC_PROG | 0x01000000)
+
+#define CHG_RPC_PROG 0x3000001a
+#define CHG_RPC_VER_1_1 0x00010001
+#define CHG_RPC_VER_1_3 0x00010003
+#define CHG_RPC_VER_2_2 0x00020002
+#define CHG_RPC_VER_3_1 0x00030001
+#define CHG_RPC_VER_4_1 0x00040001
+
+#define BATTERY_REGISTER_PROC 2
+#define BATTERY_MODIFY_CLIENT_PROC 4
+#define BATTERY_DEREGISTER_CLIENT_PROC 5
+#define BATTERY_READ_MV_PROC 12
+#define BATTERY_ENABLE_DISABLE_FILTER_PROC 14
+
+#define VBATT_FILTER 2
+
+#define BATTERY_CB_TYPE_PROC 1
+#define BATTERY_CB_ID_ALL_ACTIV 1
+#define BATTERY_CB_ID_LOW_VOL 2
+
+#define BATTERY_LOW 3400 //2800
+#define BATTERY_HIGH 4200 //4300
+
+#define ONCRPC_CHG_GET_GENERAL_STATUS_PROC 12
+#define ONCRPC_CHARGER_API_VERSIONS_PROC 0xffffffff
+
+#define BATT_RPC_TIMEOUT 5000 /* 5 sec */
+
+#define INVALID_BATT_HANDLE -1
+
+#define RPC_TYPE_REQ 0
+#define RPC_TYPE_REPLY 1
+#define RPC_REQ_REPLY_COMMON_HEADER_SIZE (3 * sizeof(uint32_t))
+
+
+/*******************************/
+/* Charging control settings */
+
+typedef enum {
+ STOP_CHARGING,
+ START_CHARGING
+} chg_enable_type;
+
+
+const int temp_table[][2] = {
+ /* ADC, Temperature (C) */
+ { 1980, -200},
+ { 1914, -150},
+ { 1845, -100},
+ { 1760, -50 },
+ { 1738, -40 },
+ { 1718, -30 },
+ { 1696, -20 },
+ { 1682, -10 },
+ { 1658, 0 },
+ { 1637, 10 },
+ { 1590, 30 },
+ { 1542, 50 },
+ { 1483, 70 },
+ { 1424, 100 },
+ { 1364, 130 },
+ { 1303, 150 },
+ { 1235, 170 },
+ { 1167, 200 },
+ { 1100, 230 },
+ { 1034, 250 },
+ { 973, 270 },
+ { 911, 300 },
+ { 855, 330 },
+ { 800, 350 },
+ { 741, 370 },
+ { 689, 400 },
+ { 654, 420 },
+ { 632, 430 },
+ { 615, 440 },
+ { 601, 450 },
+ { 517, 500 },
+ { 468, 550 },
+ { 390, 600 },
+ { 352, 640 },
+ { 345, 650 },
+ { 333, 660 },
+};
+
+
+
+#define AVERAGE_COUNT 10
+
+#define TIME_UNIT_SECOND (HZ)
+#define TIME_UNIT_MINUTE (60*HZ)
+#define TIME_UNIT_HOUR (60*60*HZ)
+
+#ifdef __FULL_CHARGE_TEST__
+#define TOTAL_CHARGING_TIME (1 * TIME_UNIT_MINUTE)
+#define TOTAL_RECHARGING_TIME (1 * TIME_UNIT_MINUTE)
+#else
+#define TOTAL_CHARGING_TIME (6 * TIME_UNIT_HOUR)
+#define TOTAL_RECHARGING_TIME (90 * TIME_UNIT_MINUTE)
+#endif
+#define TOTAL_WATING_TIME (20 * TIME_UNIT_SECOND) // wait for full-charging and recharging
+
+#define TEMP_TABLE_OFFSET 30
+#define BATT_TEMP_HIGH_BLOCK 348 // 65`C +- 2
+#define BATT_TEMP_HIGH_RECOVER 623 // 43` C +- 2
+#define BATT_TEMP_LOW_BLOCK 1708 // -3`C +- 2
+#define BATT_TEMP_LOW_RECOVER 1670 // 0`C +- 2
+
+#define BATT_FULL_CHARGING_VOLTAGE 4160
+#define BATT_FULL_CHARGING_CURRENT 180
+
+#define BATT_RECHARGING_VOLTAGE_1 4140
+#define BATT_RECHARGING_VOLTAGE_2 4000
+
+#ifdef __BATT_TEST_DEVICE__
+static int temp_test_adc = 0;
+#endif
+
+
+
+enum {
+ BATTERY_REGISTRATION_SUCCESSFUL = 0,
+ BATTERY_DEREGISTRATION_SUCCESSFUL = BATTERY_REGISTRATION_SUCCESSFUL,
+ BATTERY_MODIFICATION_SUCCESSFUL = BATTERY_REGISTRATION_SUCCESSFUL,
+ BATTERY_INTERROGATION_SUCCESSFUL = BATTERY_REGISTRATION_SUCCESSFUL,
+ BATTERY_CLIENT_TABLE_FULL = 1,
+ BATTERY_REG_PARAMS_WRONG = 2,
+ BATTERY_DEREGISTRATION_FAILED = 4,
+ BATTERY_MODIFICATION_FAILED = 8,
+ BATTERY_INTERROGATION_FAILED = 16,
+ /* Client's filter could not be set because perhaps it does not exist */
+ BATTERY_SET_FILTER_FAILED = 32,
+ /* Client's could not be found for enabling or disabling the individual
+ * client */
+ BATTERY_ENABLE_DISABLE_INDIVIDUAL_CLIENT_FAILED = 64,
+ BATTERY_LAST_ERROR = 128,
+};
+
+enum {
+ BATTERY_VOLTAGE_UP = 0,
+ BATTERY_VOLTAGE_DOWN,
+ BATTERY_VOLTAGE_ABOVE_THIS_LEVEL,
+ BATTERY_VOLTAGE_BELOW_THIS_LEVEL,
+ BATTERY_VOLTAGE_LEVEL,
+ BATTERY_ALL_ACTIVITY,
+ VBATT_CHG_EVENTS,
+ BATTERY_VOLTAGE_UNKNOWN,
+};
+
+/*
+ * This enum contains defintions of the charger hardware status
+ */
+enum chg_charger_status_type {
+ /* The charger is good */
+ CHARGER_STATUS_GOOD,
+ /* The charger is bad */
+ CHARGER_STATUS_BAD,
+ /* The charger is weak */
+ CHARGER_STATUS_WEAK,
+ /* Invalid charger status. */
+ CHARGER_STATUS_INVALID
+};
+
+/*
+ *This enum contains defintions of the charger hardware type
+ */
+enum chg_charger_hardware_type {
+ /* The charger is removed */
+ CHARGER_TYPE_NONE,
+ /* The charger is a regular wall charger */
+ CHARGER_TYPE_WALL,
+ /* The charger is a PC USB */
+ CHARGER_TYPE_USB_PC,
+ /* The charger is a wall USB charger */
+ CHARGER_TYPE_USB_WALL,
+ /* The charger is a USB carkit */
+ CHARGER_TYPE_USB_CARKIT,
+ /* Invalid charger hardware status. */
+ CHARGER_TYPE_INVALID
+};
+
+/*
+ * This enum contains defintions of the battery status
+ */
+enum chg_battery_status_type {
+ /* The battery is good */
+ BATTERY_STATUS_GOOD,
+ /* The battery is cold/hot */
+ BATTERY_STATUS_BAD_TEMP,
+ /* The battery is bad */
+ BATTERY_STATUS_BAD,
+ /* The battery is removed */
+ BATTERY_STATUS_REMOVED, /* on v2.2 only */
+ BATTERY_STATUS_INVALID_v1 = BATTERY_STATUS_REMOVED,
+ /* Invalid battery status. */
+ BATTERY_STATUS_INVALID
+};
+
+/*
+ *This enum contains defintions of the battery voltage level
+ */
+enum chg_battery_level_type {
+ /* The battery voltage is dead/very low (less than 3.2V) */
+ BATTERY_LEVEL_DEAD,
+ /* The battery voltage is weak/low (between 3.2V and 3.4V) */
+ BATTERY_LEVEL_WEAK,
+ /* The battery voltage is good/normal(between 3.4V and 4.2V) */
+ BATTERY_LEVEL_GOOD,
+ /* The battery voltage is up to full (close to 4.2V) */
+ BATTERY_LEVEL_FULL,
+ /* Invalid battery voltage level. */
+ BATTERY_LEVEL_INVALID
+};
+
+//fatory jig check 2010.08.06 Huh Won
+int batt_jig_on_status=0;
+EXPORT_SYMBOL(batt_jig_on_status);
+
+/* sys fs */
+struct class *jig_class;
+EXPORT_SYMBOL(jig_class);
+struct device *jig_dev;
+EXPORT_SYMBOL(jig_dev);
+
+static ssize_t jig_show(struct device *dev, struct device_attribute *attr, char *buf);
+static DEVICE_ATTR(jig , S_IRUGO | S_IWUSR | S_IWOTH | S_IXOTH, jig_show, NULL);
+
+static ssize_t jig_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", batt_jig_on_status );
+}
+/* sys fs */
+
+
+
+struct rpc_reply_batt_chg_v1 {
+ struct rpc_reply_hdr hdr;
+ u32 more_data;
+
+ u32 charger_status;
+ u32 charger_type;
+ u32 battery_status;
+ u32 battery_level;
+ u32 battery_voltage;
+ u32 battery_temp;
+ u32 chg_current;
+#ifdef CONFIG_WIRELESS_CHARGING
+ u32 wc_adc;
+#endif
+};
+
+struct rpc_reply_batt_chg_v2 {
+ struct rpc_reply_batt_chg_v1 v1;
+
+ u32 is_charger_valid;
+ u32 is_charging;
+ u32 is_battery_valid;
+ u32 ui_event;
+};
+
+union rpc_reply_batt_chg {
+ struct rpc_reply_batt_chg_v1 v1;
+ struct rpc_reply_batt_chg_v2 v2;
+};
+
+static union rpc_reply_batt_chg rep_batt_chg;
+
+struct msm_battery_info {
+ u32 voltage_max_design;
+ u32 voltage_min_design;
+ u32 chg_api_version;
+ u32 batt_technology;
+ u32 batt_api_version;
+
+ u32 avail_chg_sources;
+ u32 current_chg_source; // NC (charging_source)
+
+ u32 batt_status;
+ u32 batt_health;
+ u32 charger_valid; // NC
+ u32 batt_valid;
+ u32 batt_capacity; /* in percentage */
+
+ u32 charger_status; // NC
+ u32 charger_type;
+ u32 battery_status; // NC
+ u32 battery_level; // NC (batt_capacity)
+ u32 battery_voltage;
+ u32 battery_voltage_adc; // Volatage ADC
+
+ u32 fg_soc; // NC
+ u32 batt_vol; // NC (battery_voltage)
+ u32 batt_temp_check;
+ u32 batt_full_check;
+ u32 charging_source;
+
+ u32 battery_temp; /* in celsius */
+ u32 battery_temp_adc; /* ADC code from CP */
+ u32 chg_current_adc; // ICHG ADC code (charging current)
+ u32 batt_recharging;
+
+ u32 batt_wireless; // CONFIG_WIRELESS_CHARGING
+ u32 wc_adc; // CONFIG_WIRELESS_CHARGING
+
+ u32 chargingblock_clear;
+ u32 batt_voltage_now; // for low batt
+
+ u32(*calculate_capacity) (u32 voltage); // NC
+
+ s32 batt_handle;
+
+ struct power_supply *msm_psy_ac;
+ struct power_supply *msm_psy_usb;
+ struct power_supply *msm_psy_batt;
+ struct power_supply *current_ps; // NC
+
+ struct msm_rpc_client *batt_client;
+ struct msm_rpc_endpoint *chg_ep;
+
+ struct workqueue_struct *msm_batt_wq;
+ struct timer_list timer;
+
+ wait_queue_head_t wait_q;
+
+ u32 vbatt_modify_reply_avail; // NC
+
+ struct early_suspend early_suspend;
+};
+
+static struct msm_battery_info msm_batt_info = {
+ .batt_handle = INVALID_BATT_HANDLE,
+ .charger_type = CHARGER_TYPE_NONE,
+ .battery_voltage = BATTERY_HIGH,
+ .batt_capacity = 100,
+ .batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING,
+ .batt_health = POWER_SUPPLY_HEALTH_GOOD,
+ .batt_valid = 1,
+ .battery_temp = 230, // 23.0`C
+#ifdef CONFIG_WIRELESS_CHARGING
+ .batt_wireless = 0,
+ .wc_adc = 0,
+#endif
+};
+
+static enum power_supply_property msm_power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *msm_power_supplied_to[] = {
+ "battery",
+};
+
+#define BATT_CHECK_INTERVAL (5 * TIME_UNIT_SECOND) // every 5 sec
+
+static unsigned int charging_start_time = 0;
+
+static int msm_batt_driver_init = 0;
+static int msm_batt_unhandled_interrupt = 0;
+
+//Temp for USB OTG charging problem
+enum chg_type {
+ USB_CHG_TYPE__SDP,
+ USB_CHG_TYPE__CARKIT,
+ USB_CHG_TYPE__WALLCHARGER,
+ USB_CHG_TYPE__INVALID
+};
+
+extern void hsusb_chg_connected_ext(enum chg_type chgtype);
+extern void hsusb_chg_vbus_draw_ext(unsigned mA);
+extern int fsa9480_get_charger_status(void);
+extern int fsa9480_get_jig_status(void);
+
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+static u32 get_voltage_from_fuelgauge(void);
+static u32 get_level_from_fuelgauge(void);
+#endif
+
+//------------------------------
+
+int batt_restart(void);
+
+//------------------------------
+
+static ssize_t msm_batt_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t msm_batt_store_property(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static int msm_batt_average_chg_current(int chg_current_adc);
+
+static void msm_batt_check_event(struct work_struct *work);
+static void msm_batt_cable_status_update(void);
+
+/* charging absolute time control */
+static void msm_batt_set_charging_start_time(chg_enable_type enable);
+static int msm_batt_is_over_abs_time(void);
+
+static void msm_batt_update_psy_status(void);
+static DECLARE_WORK(msm_batt_work, msm_batt_check_event);
+
+static void batt_timeover(unsigned long arg )
+{
+ queue_work(msm_batt_info.msm_batt_wq, &msm_batt_work);
+ mod_timer(&msm_batt_info.timer, (jiffies + BATT_CHECK_INTERVAL));
+}
+
+static void msm_batt_check_event(struct work_struct *work)
+{
+ msm_batt_update_psy_status();
+}
+
+#define MSM_BATTERY_ATTR(_name) \
+{ \
+ .attr = { .name = #_name, .mode = 0664 }, \
+ .show = msm_batt_show_property, \
+ .store = msm_batt_store_property, \
+}
+
+static struct device_attribute ariesve_battery_attrs[] = {
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+ MSM_BATTERY_ATTR(fg_soc),
+ MSM_BATTERY_ATTR(reset_soc),
+#endif
+ MSM_BATTERY_ATTR(batt_temp_check),
+ MSM_BATTERY_ATTR(charging_source),
+ MSM_BATTERY_ATTR(batt_chg_current), // ICHG ADC code (charging current)
+#ifdef __BATT_TEST_DEVICE__
+ MSM_BATTERY_ATTR(batt_temp_test_adc),
+#endif
+#ifdef CONFIG_WIRELESS_CHARGING
+ MSM_BATTERY_ATTR(wc_status),
+ MSM_BATTERY_ATTR(wc_adc),
+#endif
+ MSM_BATTERY_ATTR(chargingblock_clear),
+};
+
+enum {
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+ FG_SOC,
+ RESET_SOC,
+#endif
+ BATT_TEMP_CHECK,
+ CHARGING_SOURCE,
+ BATT_CHG_CURRENT,
+#ifdef __BATT_TEST_DEVICE__
+ BATT_TEMP_TEST_ADC,
+#endif
+#ifdef CONFIG_WIRELESS_CHARGING
+ WC_STATUS,
+ WC_ADC,
+#endif
+ CHARGINGBLOCK_CLEAR,
+};
+
+static int msm_batt_create_attrs(struct device * dev)
+{
+ int i, rc;
+
+
+ for (i = 0; i < ARRAY_SIZE(ariesve_battery_attrs); i++)
+ {
+ rc = device_create_file(dev, &ariesve_battery_attrs[i]);
+ if (rc)
+ goto failed;
+ }
+ goto succeed;
+
+failed:
+ while (i--)
+ device_remove_file(dev, &ariesve_battery_attrs[i]);
+
+succeed:
+ return rc;
+}
+
+static void msm_batt_remove_attrs(struct device * dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ariesve_battery_attrs); i++)
+ {
+ device_remove_file(dev, &ariesve_battery_attrs[i]);
+ }
+}
+
+#if 1
+static ssize_t msm_batt_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 0;
+ const ptrdiff_t offset = attr - ariesve_battery_attrs;
+
+ switch (offset) {
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+ case FG_SOC:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ get_level_from_fuelgauge());
+ break;
+ case RESET_SOC :
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ fg_reset_soc());
+ break;
+#endif
+ case BATT_TEMP_CHECK:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ msm_batt_info.batt_temp_check);
+ break;
+ case CHARGING_SOURCE:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ msm_batt_info.charging_source);
+ break;
+ case BATT_CHG_CURRENT: // ICHG ADC code (charging current)
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ msm_batt_info.chg_current_adc);
+ break;
+#ifdef __BATT_TEST_DEVICE__
+ case BATT_TEMP_TEST_ADC:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", temp_test_adc);
+ break;
+#endif
+#ifdef CONFIG_WIRELESS_CHARGING
+ case WC_STATUS:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ msm_batt_info.batt_wireless);
+ break;
+ case WC_ADC:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ msm_batt_info.wc_adc);
+ break;
+#endif
+ case CHARGINGBLOCK_CLEAR:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", msm_batt_info.chargingblock_clear);
+ break;
+ default:
+ i = -EINVAL;
+ }
+
+ return i;
+}
+
+static ssize_t msm_batt_store_property(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int x = 0;
+ int ret = 0;
+ const ptrdiff_t offset = attr - ariesve_battery_attrs;
+
+
+ switch (offset) {
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+ case RESET_SOC:
+ if (sscanf(buf, "%d\n", &x) == 1) {
+ fg_reset_soc(); // rilactionservice.java...
+ ret = count;
+ }
+ break;
+#endif
+#ifdef __BATT_TEST_DEVICE__
+ case BATT_TEMP_TEST_ADC:
+ if (sscanf(buf, "%d\n", &x) == 1) {
+ if (x == 0)
+ temp_test_adc = 0;
+ else
+ {
+ temp_test_adc = x;
+ }
+ ret = count;
+ }
+ break;
+#endif
+ case CHARGINGBLOCK_CLEAR:
+ if (sscanf(buf, "%d\n", &x) == 1) {
+ pr_debug("\n[BATT] %s: chargingblock_clear -> write 0x%x\n\n", __func__, x);
+ msm_batt_info.chargingblock_clear = x;
+ ret = count;
+ }
+ break;
+ default:
+ return -EINVAL;
+ } /* end of switch */
+
+ return ret;
+}
+#endif
+
+static int msm_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
+ val->intval = msm_batt_info.charging_source & AC_CHG
+ ? 1 : 0;
+ }
+ if (psy->type == POWER_SUPPLY_TYPE_USB) {
+ val->intval = msm_batt_info.charging_source & USB_CHG
+ ? 1 : 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct power_supply msm_psy_ac = {
+ .name = "ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .supplied_to = msm_power_supplied_to,
+ .num_supplicants = ARRAY_SIZE(msm_power_supplied_to),
+ .properties = msm_power_props,
+ .num_properties = ARRAY_SIZE(msm_power_props),
+ .get_property = msm_power_get_property,
+};
+
+static struct power_supply msm_psy_usb = {
+ .name = "usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .supplied_to = msm_power_supplied_to,
+ .num_supplicants = ARRAY_SIZE(msm_power_supplied_to),
+ .properties = msm_power_props,
+ .num_properties = ARRAY_SIZE(msm_power_props),
+ .get_property = msm_power_get_property,
+};
+
+static enum power_supply_property msm_batt_power_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_BATT_TEMP,
+ POWER_SUPPLY_PROP_BATT_TEMP_ADC,
+ POWER_SUPPLY_PROP_BATT_VOL,
+ POWER_SUPPLY_PROP_BATT_VOL_ADC,
+ POWER_SUPPLY_PROP_BATT_VF_ADC,
+ POWER_SUPPLY_PROP_BATT_VOL_ADC_AVER,
+ POWER_SUPPLY_PROP_BATT_TEMP_ADC_AVER,
+ POWER_SUPPLY_PROP_BATT_VOL_AVER,
+ POWER_SUPPLY_PROP_BATT_TEMP_AVER,
+ POWER_SUPPLY_PROP_BATT_TYPE,
+ POWER_SUPPLY_PROP_BATT_FULL,
+};
+
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+static u32 get_voltage_from_fuelgauge(void)
+{
+ if (is_attached)
+ return (fg_read_vcell()); // +0 (voltage drop compensation)
+ return 3700; // default
+}
+
+static u32 get_level_from_fuelgauge(void)
+{
+ if (is_attached)
+ return fg_read_soc();
+ return 100; // default
+}
+#endif
+
+static int msm_batt_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = msm_batt_info.batt_status;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = msm_batt_info.batt_health;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = msm_batt_info.batt_valid;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = msm_batt_info.batt_technology;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = msm_batt_info.voltage_max_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = msm_batt_info.voltage_min_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = msm_batt_info.batt_voltage_now;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = msm_batt_info.batt_capacity;
+ break;
+ case POWER_SUPPLY_PROP_BATT_TEMP:
+ val->intval = msm_batt_info.battery_temp;
+ break;
+ case POWER_SUPPLY_PROP_BATT_TEMP_ADC:
+ val->intval = msm_batt_info.battery_temp_adc;
+ break;
+ case POWER_SUPPLY_PROP_BATT_VOL:
+ val->intval = msm_batt_info.battery_voltage;
+ break;
+ case POWER_SUPPLY_PROP_BATT_VOL_ADC:
+ val->intval = msm_batt_info.battery_voltage_adc;
+ break;
+ case POWER_SUPPLY_PROP_BATT_VF_ADC:
+// val->intval = msm_batt_info.battery_vf;
+ break;
+ case POWER_SUPPLY_PROP_BATT_VOL_ADC_AVER:
+ val->intval = msm_batt_info.battery_level;
+ break;
+ case POWER_SUPPLY_PROP_BATT_TEMP_ADC_AVER:
+ val->intval = msm_batt_info.battery_temp;
+ break;
+ case POWER_SUPPLY_PROP_BATT_VOL_AVER:
+ val->intval = msm_batt_info.battery_voltage;
+ break;
+ case POWER_SUPPLY_PROP_BATT_TEMP_AVER:
+ val->intval = msm_batt_info.battery_temp_adc;
+ break;
+ case POWER_SUPPLY_PROP_BATT_TYPE:
+ break;
+ case POWER_SUPPLY_PROP_BATT_FULL:
+ val->intval = msm_batt_info.batt_full_check;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct power_supply msm_psy_batt = {
+ .name = "battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = msm_batt_power_props,
+ .num_properties = ARRAY_SIZE(msm_batt_power_props),
+ .get_property = msm_batt_power_get_property,
+};
+
+#ifdef MAX17043_FUEL_GAUGE
+struct timer_list fg_alert_timer;
+extern int (*fg_alert_handler)(int);
+static void fg_set_alert_ext(unsigned long arg)
+{
+
+ if (msm_batt_info.charging_source == NO_CHG)
+ {
+ pr_info("[BATT] %s: low battery, power off...\n", __func__);
+ is_alert = 1;
+ wake_lock_timeout(&vbus_wake_lock, 30 * TIME_UNIT_SECOND);
+ }
+ else
+ is_alert = 0;
+}
+
+static int fg_set_alert(int value)
+{
+
+ if (value)
+ {
+ is_alert =
+ mod_timer(&fg_alert_timer, (jiffies + (1 * TIME_UNIT_MINUTE)));
+// is_alert = 1;
+// wake_lock_timeout(&vbus_wake_lock, 30 * TIME_UNIT_SECOND);
+ }
+ else
+ {
+ // clear alert flag
+ is_alert = 0;
+ }
+
+ return is_alert;
+}
+
+
+#endif /* MAX17043_FUEL_GAUGE */
+
+static void msm_batt_chg_en(chg_enable_type enable)
+{
+
+ if (enable == START_CHARGING)
+ {
+ if (msm_batt_info.charging_source == NO_CHG) // *Note: DO NOT USE "&" operation for NO_CHG (0x0), it returns FALSE always.
+ {
+ pr_err("[BATT] %s: charging_source not defined!\n", __func__);
+ return ;
+ }
+
+ // Set charging current (ICHG; mA)
+ if (msm_batt_info.charging_source & AC_CHG)
+ {
+ pr_info("[BATT] %s: Start charging! (charging_source = AC, wireless = %d)\n", __func__, msm_batt_info.batt_wireless);
+ hsusb_chg_connected_ext(USB_CHG_TYPE__WALLCHARGER);
+#ifdef CONFIG_WIRELESS_CHARGING
+ if (msm_batt_info.batt_wireless)
+ hsusb_chg_vbus_draw_ext(500); // wireless charging (450mA)
+ else
+#endif
+ hsusb_chg_vbus_draw_ext(650); // TA charging (600mA)
+ }
+ else // USB_CHG
+ {
+ pr_info("[BATT] %s: Start charging! (charging_source = USB)\n", __func__);
+ hsusb_chg_connected_ext(USB_CHG_TYPE__SDP);
+ //hsusb_chg_vbus_draw_ext(450); // USB charging (400mA)
+ hsusb_chg_vbus_draw_ext(500); // USB charging (450mA)
+ }
+
+ msm_batt_set_charging_start_time(START_CHARGING);
+#ifdef MAX17043_FUEL_GAUGE
+ fg_set_alert(0);
+#endif
+ }
+ else // STOP_CHARGING
+ {
+ msm_batt_set_charging_start_time(STOP_CHARGING);
+
+ if (msm_batt_info.charging_source == NO_CHG)
+ hsusb_chg_connected_ext(USB_CHG_TYPE__INVALID); // not charging
+ else
+ hsusb_chg_vbus_draw_ext(0); // discharging
+
+ msm_batt_average_chg_current(-1); // Initialize all current data sampling
+
+ pr_info("[BATT] %s: Stop charging! (charging_source = 0x%x, full_check = %d)\n",
+ __func__, msm_batt_info.charging_source, msm_batt_info.batt_full_check);
+ }
+}
+
+static int msm_batt_average_chg_current(int chg_current_adc)
+{
+ static int history[AVERAGE_COUNT] = {0};
+ static int count = 0;
+ static int index = 0;
+ int i, sum, max, min, ret;
+
+
+
+ if (chg_current_adc == 0)
+ return 0;
+
+ if (chg_current_adc < 0) // initialize all data
+ {
+ count = 0;
+ index = 0;
+ for (i=0; i<AVERAGE_COUNT; i++) history[i] = 0;
+
+ return 0;
+ }
+
+ if (count == 0) // no data
+ {
+ for (i=0; i<AVERAGE_COUNT; i++) history[i] = chg_current_adc;
+ }
+
+ if (index >= count) count++;
+
+ max = min = history[0];
+ sum = 0;
+
+ for (i=0; i<AVERAGE_COUNT; i++)
+ {
+ if (i == index)
+ {
+ history[i] = chg_current_adc;
+ }
+
+ if (max < history[i]) max = history[i];
+ if (min > history[i]) min = history[i];
+
+ sum += history[i];
+ }
+
+ ret = ((sum-max-min) / (AVERAGE_COUNT-2));
+
+ index++;
+ if (index == AVERAGE_COUNT)
+ {
+ history[0] = ret;
+ index = 1;
+ }
+
+ pr_debug("[BATT] %s: adc=%d, sum=%d, max=%d, min=%d, ret=%d\n", __func__, chg_current_adc, sum, max, min, ret);
+
+ if (count < AVERAGE_COUNT)
+ return (BATT_FULL_CHARGING_CURRENT+50); // do not check full charging before current sampling is stable...
+
+ return ret;
+}
+
+static int msm_batt_check_full_charging(int chg_current_adc)
+{
+ static unsigned int time_after_under_tsh = 0;
+
+ if (chg_current_adc == 0)
+ return 0; // not charging
+
+ // check charging absolute time
+ if (msm_batt_is_over_abs_time())
+ {
+ pr_info("[BATT] %s: Fully charged, over abs time! (recharging=%d)\n", __func__, msm_batt_info.batt_recharging);
+ msm_batt_info.batt_full_check = 0;
+ msm_batt_info.batt_recharging = 1;
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ msm_batt_chg_en(STOP_CHARGING);
+ return 1;
+ }
+
+ if (msm_batt_info.battery_voltage >= BATT_FULL_CHARGING_VOLTAGE)
+ {
+ // check charging current threshold
+ if (chg_current_adc < BATT_FULL_CHARGING_CURRENT)
+ {
+ if (time_after_under_tsh == 0)
+ time_after_under_tsh = jiffies;
+ else
+ {
+ if (time_after((unsigned long)jiffies, (unsigned long)(time_after_under_tsh + TOTAL_WATING_TIME)))
+ {
+ // fully charged !
+ pr_info("[BATT] %s: Fully charged, cut off charging current! (voltage=%d, ICHG=%d)\n",
+ __func__, msm_batt_info.battery_voltage, chg_current_adc);
+ msm_batt_info.batt_full_check = 1;
+ msm_batt_info.batt_recharging = 0;
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_FULL;
+ time_after_under_tsh = 0;
+ msm_batt_chg_en(STOP_CHARGING);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ time_after_under_tsh = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int msm_batt_check_recharging(void)
+{
+ static unsigned int time_after_vol1 = 0, time_after_vol2 = 0;
+
+
+ if ( (msm_batt_info.batt_full_check == 0) ||
+ (msm_batt_info.batt_recharging == 1) ||
+ (msm_batt_info.batt_health != POWER_SUPPLY_HEALTH_GOOD) )
+ {
+ time_after_vol1 = 0;
+ time_after_vol2 = 0;
+ return 0;
+ }
+
+ /* check 1st voltage */
+ if (msm_batt_info.battery_voltage <= BATT_RECHARGING_VOLTAGE_1)
+ {
+ if (time_after_vol1 == 0)
+ time_after_vol1 = jiffies;
+
+ if (time_after((unsigned long)jiffies, (unsigned long)(time_after_vol1 + TOTAL_WATING_TIME)))
+ {
+ pr_info("[BATT] %s: Recharging ! (voltage1 = %d)\n", __func__, msm_batt_info.battery_voltage);
+ msm_batt_info.batt_recharging = 1;
+ msm_batt_chg_en(START_CHARGING);
+ return 1;
+ }
+ }
+ else
+ time_after_vol1 = 0;
+
+ /* check 2nd voltage */
+ if (msm_batt_info.battery_voltage <= BATT_RECHARGING_VOLTAGE_2)
+ {
+ if (time_after_vol2 == 0)
+ time_after_vol2 = jiffies;
+
+ if (time_after((unsigned long)jiffies, (unsigned long)(time_after_vol2 + TOTAL_WATING_TIME)))
+ {
+ pr_info("[BATT] %s: Recharging ! (voltage2 = %d)\n", __func__, msm_batt_info.battery_voltage);
+ msm_batt_info.batt_recharging = 1;
+ msm_batt_chg_en(START_CHARGING);
+ return 1;
+ }
+ }
+ else
+ time_after_vol2 = 0;
+
+ return 0;
+}
+
+static int msm_batt_check_level(int battery_level)
+{
+ if (msm_batt_info.batt_full_check == 0 && battery_level == 100)
+ battery_level = 99; // not yet fully charged
+
+ if (msm_batt_info.batt_capacity != battery_level)
+ {
+ pr_info("[BATT] %s: Battery level changed ! (%d -> %d)\n", __func__, msm_batt_info.batt_capacity, battery_level);
+ msm_batt_info.batt_capacity = battery_level;
+ return 1;
+ }
+
+#ifdef MAX17043_FUEL_GAUGE
+ if (is_alert)
+ return 1; // force update to power off !
+#endif
+
+ return 0;
+}
+
+static int msm_batt_average_temperature(int temp_adc)
+{
+ static int history[AVERAGE_COUNT] = {0};
+ static int count = 0;
+ static int index = 0;
+ int i, sum, max, min, ret;
+
+ if (temp_adc == 0)
+ return 0;
+
+ if (count == 0 && temp_adc == 150)
+ return 0;
+
+#ifdef __BATT_TEST_DEVICE__
+ if (temp_test_adc)
+ return temp_test_adc;
+#endif
+
+ if (count == 0) // no data
+ {
+ for (i=0; i<AVERAGE_COUNT; i++) history[i] = temp_adc;
+ }
+
+ if (index >= count) count++;
+
+ max = min = history[0];
+ sum = 0;
+
+ for (i=0; i<AVERAGE_COUNT; i++)
+ {
+ if (i == index)
+ {
+ history[i] = temp_adc;
+ }
+
+ if (max < history[i]) max = history[i];
+ if (min > history[i]) min = history[i];
+
+ sum += history[i];
+ }
+
+ ret = ((sum-max-min) / (AVERAGE_COUNT-2));
+
+ index++;
+ if (index == AVERAGE_COUNT)
+ {
+ history[0] = ret;
+ index = 1;
+ }
+
+ pr_debug("[BATT] %s: adc=%d, sum=%d, max=%d, min=%d, ret=%d\n", __func__, temp_adc, sum, max, min, ret);
+ return ret;
+}
+
+static int msm_batt_control_temperature(int temp_adc)
+{
+ int prev_health = msm_batt_info.batt_health;
+ int new_health = prev_health;
+ int array_size = 0;
+ int i;
+ int degree;
+
+
+ static char *health_text[] = {
+ "Unknown", "Good", "Overheat", "Dead", "Over voltage",
+ "Unspecified failure", "Cold",
+ };
+
+ if (temp_adc == 0)
+ return 0;
+
+#ifdef __AUTO_TEMP_TEST__
+ static unsigned int auto_test_start_time = 0;
+ static unsigned int auto_test_interval = (2 * TIME_UNIT_MINUTE);
+ static int auto_test_mode = 0; // 0: normal (recover cold), 1: force overheat, 2: normal (recover overheat), 3: force cold
+
+ if (msm_batt_info.charging_source != NO_CHG) // charging
+ {
+ if (auto_test_start_time == 0)
+ auto_test_start_time = jiffies;
+
+ if (time_after((unsigned long)jiffies, (unsigned long)(auto_test_start_time + auto_test_interval)))
+ {
+ auto_test_mode++;
+ if (auto_test_mode > 3) auto_test_mode = 0;
+ auto_test_start_time = jiffies;
+ }
+ pr_debug("[BATT] auto test mode = %d (0:normal,1:overheat,2:normal,3:cold)\n", auto_test_mode);
+
+ if (auto_test_mode == 1)
+ {
+ temp_adc = BATT_TEMP_HIGH_BLOCK + 10;
+ msm_batt_info.battery_temp_adc = temp_adc;
+ }
+ else if (auto_test_mode == 3)
+ {
+ temp_adc = BATT_TEMP_LOW_BLOCK - 10;
+ msm_batt_info.battery_temp_adc = temp_adc;
+ }
+ }
+ else // not charging
+ {
+ auto_test_start_time = 0;
+ auto_test_mode = 0;
+ }
+#endif
+
+ // map in celcius degree
+ array_size = ARRAY_SIZE(temp_table);
+ for (i = 0; i <= (array_size - 1); i++)
+ {
+ if (i == 0)
+ {
+ if (temp_adc >= temp_table[0][0])
+ {
+ degree = temp_table[0][1];
+ break;
+ }
+ else if (temp_adc <= temp_table[array_size-1][0])
+ {
+ degree = temp_table[array_size-1][1];
+ break;
+ }
+ }
+
+ if (temp_table[i][0] < temp_adc && temp_table[i-1][0] >= temp_adc)
+ {
+ degree = temp_table[i-1][1];
+ }
+ }
+
+ msm_batt_info.battery_temp = degree; // celcius degree
+
+ // TODO: check application
+
+ if (prev_health == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)
+ {
+ return 0; // do not check temperature... (charging is already blocked!)
+ }
+
+ if (temp_adc <= BATT_TEMP_HIGH_BLOCK)
+ {
+ // over high block
+ if (prev_health != POWER_SUPPLY_HEALTH_OVERHEAT)
+ new_health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ }
+ else if ((temp_adc >= BATT_TEMP_HIGH_RECOVER) && (temp_adc <= BATT_TEMP_LOW_RECOVER))
+ {
+ // low recover ~ high recover (normal)
+ if ( (prev_health == POWER_SUPPLY_HEALTH_OVERHEAT) ||
+ (prev_health == POWER_SUPPLY_HEALTH_COLD) )
+ new_health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ else if (temp_adc >= BATT_TEMP_LOW_BLOCK)
+ {
+ // under low block
+ if (prev_health != POWER_SUPPLY_HEALTH_COLD)
+ new_health = POWER_SUPPLY_HEALTH_COLD;
+ }
+
+ if (msm_batt_info.charging_source == NO_CHG)
+ {
+ if ((BATT_TEMP_LOW_BLOCK > temp_adc) && (temp_adc > BATT_TEMP_HIGH_BLOCK))
+ {
+ if ( (prev_health == POWER_SUPPLY_HEALTH_OVERHEAT) ||
+ (prev_health == POWER_SUPPLY_HEALTH_COLD) )
+ new_health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ }
+
+ if (msm_batt_info.chargingblock_clear != 0x0)
+ new_health = POWER_SUPPLY_HEALTH_GOOD;
+
+ if (prev_health != new_health)
+ {
+ if (msm_batt_info.charging_source == NO_CHG) // not charging
+ {
+ pr_info("[BATT] %s: Health changed by temperature! (ADC = %d, %s-> %s)\n",
+ __func__, temp_adc, health_text[prev_health], health_text[new_health]);
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+ else // in charging
+ {
+ if (new_health != POWER_SUPPLY_HEALTH_GOOD) // block!
+ {
+ pr_info("[BATT] %s: Block charging! (ADC = %d, %s-> %s)\n",
+ __func__, temp_adc, health_text[prev_health], health_text[new_health]);
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ msm_batt_chg_en(STOP_CHARGING);
+ }
+ else if (msm_batt_info.batt_full_check == 0) // recover!
+ {
+ pr_info("[BATT] %s: Recover charging! (ADC = %d, %s-> %s)\n",
+ __func__, temp_adc, health_text[prev_health], health_text[new_health]);
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_CHARGING;
+ msm_batt_chg_en(START_CHARGING);
+ }
+ }
+
+ msm_batt_info.batt_health = new_health;
+ }
+
+ return 1;
+// return 0; // nothing is changed
+}
+
+#define be32_to_cpu_self(v) (v = be32_to_cpu(v))
+#define be16_to_cpu_self(v) (v = be16_to_cpu(v))
+
+static int msm_batt_get_batt_chg_status(void)
+{
+ int rc ;
+ struct rpc_req_batt_chg {
+ struct rpc_request_hdr hdr;
+ u32 more_data;
+ } req_batt_chg;
+ struct rpc_reply_batt_chg_v1 *v1p;
+
+
+ req_batt_chg.more_data = cpu_to_be32(1);
+
+ memset(&rep_batt_chg, 0, sizeof(rep_batt_chg));
+
+ v1p = &rep_batt_chg.v1;
+ rc = msm_rpc_call_reply(msm_batt_info.chg_ep,
+ ONCRPC_CHG_GET_GENERAL_STATUS_PROC,
+ &req_batt_chg, sizeof(req_batt_chg),
+ &rep_batt_chg, sizeof(rep_batt_chg),
+ msecs_to_jiffies(BATT_RPC_TIMEOUT));
+ if (rc < 0) {
+ pr_err("%s: ERROR. msm_rpc_call_reply failed! proc=%d rc=%d\n",
+ __func__, ONCRPC_CHG_GET_GENERAL_STATUS_PROC, rc);
+ return rc;
+ } else if (be32_to_cpu(v1p->more_data)) {
+ be32_to_cpu_self(v1p->charger_status);
+ be32_to_cpu_self(v1p->charger_type);
+ be32_to_cpu_self(v1p->battery_status);
+ be32_to_cpu_self(v1p->battery_level);
+ be32_to_cpu_self(v1p->battery_voltage);
+ be32_to_cpu_self(v1p->battery_temp);
+ be32_to_cpu_self(v1p->chg_current);
+#ifdef CONFIG_WIRELESS_CHARGING
+ be32_to_cpu_self(v1p->wc_adc);
+#endif
+ } else {
+ pr_err("%s: No battery/charger data in RPC reply\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void msm_batt_update_psy_status(void)
+{
+ u32 charger_status;
+ u32 charger_type;
+ u32 battery_status;
+ u32 battery_level;
+ u32 fuel_battery_voltage;
+ u32 battery_voltage_adc;
+ u32 battery_temp_adc;
+ u32 chg_current_adc;
+#ifdef CONFIG_WIRELESS_CHARGING
+ u32 wc_adc;
+#endif
+
+ u32 status_changed = 0;
+
+ /*
+ // Check LPM mode
+ if(charging_boot)
+ {
+ msm_batt_info.batt_voltage_now = charging_boot;
+ msm_batt_info.batt_status = 0;
+ }
+ */
+
+ /* Get general status from CP by RPC */
+ if (msm_batt_get_batt_chg_status())
+ return;
+
+ charger_status = rep_batt_chg.v1.charger_status;
+ charger_type = rep_batt_chg.v1.charger_type;
+ battery_status = rep_batt_chg.v1.battery_status;
+ battery_temp_adc = rep_batt_chg.v1.battery_temp;
+// chg_current_adc = rep_batt_chg.v1.chg_current;
+ chg_current_adc = battery_voltage_adc = rep_batt_chg.v1.battery_voltage; // Use voltage for current adc
+
+ msm_batt_info.battery_voltage_adc = battery_voltage_adc;
+ msm_batt_info.battery_temp_adc = battery_temp_adc;
+
+#ifdef CONFIG_WIRELESS_CHARGING
+ wc_adc = rep_batt_chg.v1.wc_adc;
+ wc_adc = wc_adc * 46 / 160; // HW req.
+#endif
+
+ if ( (msm_batt_info.batt_status == POWER_SUPPLY_STATUS_CHARGING) ||
+ (msm_batt_info.batt_recharging == 1) )
+ {
+ pr_debug("[BATT] %s: chg_current_adc from CP = %d\n", __func__, chg_current_adc);
+ if (chg_current_adc < 30)
+ chg_current_adc = 0;
+ }
+ else
+ chg_current_adc = 0; // not charging
+
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+ battery_level = get_level_from_fuelgauge();
+ fuel_battery_voltage = get_voltage_from_fuelgauge();
+#endif
+
+ msm_batt_info.battery_voltage = fuel_battery_voltage;
+ msm_batt_info.batt_voltage_now = fuel_battery_voltage;
+
+#ifdef CONFIG_WIRELESS_CHARGING
+ msm_batt_info.wc_adc = wc_adc;
+#endif
+
+ /**************************/
+ /* Check what is changed */
+
+ /* check temperature */
+// msm_batt_info.battery_temp_adc = msm_batt_average_temperature(battery_temp_adc);
+ status_changed += msm_batt_control_temperature(msm_batt_info.battery_temp_adc);
+
+ /* check full charging */
+ msm_batt_info.chg_current_adc = msm_batt_average_chg_current(chg_current_adc);
+ status_changed += msm_batt_check_full_charging(msm_batt_info.chg_current_adc);
+
+ /* check recharging */
+ status_changed += msm_batt_check_recharging();
+
+ /* battery level, capacity (%) */
+ status_changed += msm_batt_check_level(battery_level);
+
+ /* temperature health for power off charging */
+ if (msm_batt_info.batt_health == POWER_SUPPLY_HEALTH_GOOD)
+ msm_batt_info.batt_temp_check = 1;
+ else
+ msm_batt_info.batt_temp_check = 0;
+
+#ifndef DEBUG
+ if (msm_batt_info.charging_source != NO_CHG)
+#endif
+ {
+ pr_info("[BATT] %s: charger_status=%d, charger_type=%d, battery_status=%d, battery_temp_adc=%d, chg_current=%d, wc_adc=%d\n",
+ __func__, charger_status, charger_type, battery_status, msm_batt_info.battery_temp_adc, msm_batt_info.chg_current_adc, msm_batt_info.wc_adc);
+ }
+
+ if (status_changed)
+ {
+ pr_info("[BATT] %s: power_supply_changed !\n", __func__);
+ power_supply_changed(&msm_psy_batt);
+ }
+
+ if (msm_batt_unhandled_interrupt)
+ {
+ msm_batt_cable_status_update();
+ msm_batt_unhandled_interrupt = 0;
+ }
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct batt_modify_client_req {
+
+ u32 client_handle;
+
+ /* The voltage at which callback (CB) should be called. */
+ u32 desired_batt_voltage;
+
+ /* The direction when the CB should be called. */
+ u32 voltage_direction;
+
+ /* The registered callback to be called when voltage and
+ * direction specs are met. */
+ u32 batt_cb_id;
+
+ /* The call back data */
+ u32 cb_data;
+};
+
+struct batt_modify_client_rep {
+ u32 result;
+};
+
+static int msm_batt_modify_client_arg_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_modify_client_req *batt_modify_client_req =
+ (struct batt_modify_client_req *)data;
+ u32 *req = (u32 *)buf;
+ int size = 0;
+
+
+
+ *req = cpu_to_be32(batt_modify_client_req->client_handle);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_modify_client_req->desired_batt_voltage);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_modify_client_req->voltage_direction);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_modify_client_req->batt_cb_id);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_modify_client_req->cb_data);
+ size += sizeof(u32);
+
+ return size;
+}
+
+static int msm_batt_modify_client_ret_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_modify_client_rep *data_ptr, *buf_ptr;
+
+
+
+ data_ptr = (struct batt_modify_client_rep *)data;
+ buf_ptr = (struct batt_modify_client_rep *)buf;
+
+ data_ptr->result = be32_to_cpu(buf_ptr->result);
+
+ return 0;
+}
+
+static int msm_batt_modify_client(u32 client_handle, u32 desired_batt_voltage,
+ u32 voltage_direction, u32 batt_cb_id, u32 cb_data)
+{
+ int rc;
+
+ struct batt_modify_client_req req;
+ struct batt_modify_client_rep rep;
+
+ req.client_handle = client_handle;
+ req.desired_batt_voltage = desired_batt_voltage;
+ req.voltage_direction = voltage_direction;
+ req.batt_cb_id = batt_cb_id;
+ req.cb_data = cb_data;
+
+
+ rc = msm_rpc_client_req(msm_batt_info.batt_client,
+ BATTERY_MODIFY_CLIENT_PROC,
+ msm_batt_modify_client_arg_func, &req,
+ msm_batt_modify_client_ret_func, &rep,
+ msecs_to_jiffies(BATT_RPC_TIMEOUT));
+
+ if (rc < 0) {
+ pr_err("%s: ERROR. failed to modify Vbatt client\n",
+ __func__);
+ return rc;
+ }
+
+ if (rep.result != BATTERY_MODIFICATION_SUCCESSFUL) {
+ pr_err("%s: ERROR. modify client failed. result = %u\n",
+ __func__, rep.result);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void msm_batt_early_suspend(struct early_suspend *h)
+{
+ int rc;
+
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (msm_batt_info.batt_handle != INVALID_BATT_HANDLE) {
+ rc = msm_batt_modify_client(msm_batt_info.batt_handle,
+ BATTERY_LOW, BATTERY_VOLTAGE_BELOW_THIS_LEVEL,
+ BATTERY_CB_ID_LOW_VOL, BATTERY_LOW);
+
+ if (rc < 0) {
+ pr_err("%s: msm_batt_modify_client. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+ } else {
+ pr_err("%s: ERROR. invalid batt_handle\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: exit\n", __func__);
+}
+
+void msm_batt_late_resume(struct early_suspend *h)
+{
+ int rc;
+
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (msm_batt_info.batt_handle != INVALID_BATT_HANDLE) {
+ rc = msm_batt_modify_client(msm_batt_info.batt_handle,
+ BATTERY_LOW, BATTERY_ALL_ACTIVITY,
+ BATTERY_CB_ID_ALL_ACTIV, BATTERY_ALL_ACTIVITY);
+ if (rc < 0) {
+ pr_err("%s: msm_batt_modify_client FAIL rc=%d\n",
+ __func__, rc);
+ return;
+ }
+ } else {
+ pr_err("%s: ERROR. invalid batt_handle\n", __func__);
+ return;
+ }
+
+ msm_batt_update_psy_status();
+ pr_debug("%s: exit\n", __func__);
+}
+#endif
+
+struct msm_batt_vbatt_filter_req {
+ u32 batt_handle;
+ u32 enable_filter;
+ u32 vbatt_filter;
+};
+
+struct msm_batt_vbatt_filter_rep {
+ u32 result;
+};
+
+static int msm_batt_filter_arg_func(struct msm_rpc_client *batt_client,
+
+ void *buf, void *data)
+{
+ struct msm_batt_vbatt_filter_req *vbatt_filter_req =
+ (struct msm_batt_vbatt_filter_req *)data;
+ u32 *req = (u32 *)buf;
+ int size = 0;
+
+
+ *req = cpu_to_be32(vbatt_filter_req->batt_handle);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(vbatt_filter_req->enable_filter);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(vbatt_filter_req->vbatt_filter);
+ size += sizeof(u32);
+ return size;
+}
+
+static int msm_batt_filter_ret_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+
+ struct msm_batt_vbatt_filter_rep *data_ptr, *buf_ptr;
+
+
+ data_ptr = (struct msm_batt_vbatt_filter_rep *)data;
+ buf_ptr = (struct msm_batt_vbatt_filter_rep *)buf;
+
+ data_ptr->result = be32_to_cpu(buf_ptr->result);
+ return 0;
+}
+
+static int msm_batt_enable_filter(u32 vbatt_filter)
+{
+ int rc;
+ struct msm_batt_vbatt_filter_req vbatt_filter_req;
+ struct msm_batt_vbatt_filter_rep vbatt_filter_rep;
+
+
+ vbatt_filter_req.batt_handle = msm_batt_info.batt_handle;
+ vbatt_filter_req.enable_filter = 1;
+ vbatt_filter_req.vbatt_filter = vbatt_filter;
+
+ rc = msm_rpc_client_req(msm_batt_info.batt_client,
+ BATTERY_ENABLE_DISABLE_FILTER_PROC,
+ msm_batt_filter_arg_func, &vbatt_filter_req,
+ msm_batt_filter_ret_func, &vbatt_filter_rep,
+ msecs_to_jiffies(BATT_RPC_TIMEOUT));
+
+ if (rc < 0) {
+ pr_err("%s: FAIL: enable vbatt filter. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (vbatt_filter_rep.result != BATTERY_DEREGISTRATION_SUCCESSFUL) {
+ pr_err("%s: FAIL: enable vbatt filter: result=%d\n",
+ __func__, vbatt_filter_rep.result);
+ return -EIO;
+ }
+
+ pr_debug("%s: enable vbatt filter: OK\n", __func__);
+ return rc;
+}
+
+struct batt_client_registration_req {
+ /* The voltage at which callback (CB) should be called. */
+ u32 desired_batt_voltage;
+
+ /* The direction when the CB should be called. */
+ u32 voltage_direction;
+
+ /* The registered callback to be called when voltage and
+ * direction specs are met. */
+ u32 batt_cb_id;
+
+ /* The call back data */
+ u32 cb_data;
+ u32 more_data;
+ u32 batt_error;
+};
+
+struct batt_client_registration_rep {
+ u32 batt_handle;
+};
+
+static int msm_batt_register_arg_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_client_registration_req *batt_reg_req =
+ (struct batt_client_registration_req *)data;
+ u32 *req = (u32 *)buf;
+ int size = 0;
+
+
+
+ *req = cpu_to_be32(batt_reg_req->desired_batt_voltage);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_reg_req->voltage_direction);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_reg_req->batt_cb_id);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_reg_req->cb_data);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_reg_req->more_data);
+ size += sizeof(u32);
+ req++;
+
+ *req = cpu_to_be32(batt_reg_req->batt_error);
+ size += sizeof(u32);
+
+ return size;
+}
+
+static int msm_batt_register_ret_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_client_registration_rep *data_ptr, *buf_ptr;
+
+
+ data_ptr = (struct batt_client_registration_rep *)data;
+ buf_ptr = (struct batt_client_registration_rep *)buf;
+
+ data_ptr->batt_handle = be32_to_cpu(buf_ptr->batt_handle);
+
+ return 0;
+}
+
+static int msm_batt_register(u32 desired_batt_voltage,
+ u32 voltage_direction, u32 batt_cb_id, u32 cb_data)
+{
+ struct batt_client_registration_req batt_reg_req;
+ struct batt_client_registration_rep batt_reg_rep;
+ int rc;
+
+
+ batt_reg_req.desired_batt_voltage = desired_batt_voltage;
+ batt_reg_req.voltage_direction = voltage_direction;
+ batt_reg_req.batt_cb_id = batt_cb_id;
+ batt_reg_req.cb_data = cb_data;
+ batt_reg_req.more_data = 1;
+ batt_reg_req.batt_error = 0;
+
+ rc = msm_rpc_client_req(msm_batt_info.batt_client,
+ BATTERY_REGISTER_PROC,
+ msm_batt_register_arg_func, &batt_reg_req,
+ msm_batt_register_ret_func, &batt_reg_rep,
+ msecs_to_jiffies(BATT_RPC_TIMEOUT));
+
+ if (rc < 0) {
+ pr_err("%s: FAIL: vbatt register. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ msm_batt_info.batt_handle = batt_reg_rep.batt_handle;
+
+ pr_debug("%s: got handle = %d\n", __func__, msm_batt_info.batt_handle);
+
+ return 0;
+}
+
+struct batt_client_deregister_req {
+ u32 batt_handle;
+};
+
+struct batt_client_deregister_rep {
+ u32 batt_error;
+};
+
+static int msm_batt_deregister_arg_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_client_deregister_req *deregister_req =
+ (struct batt_client_deregister_req *)data;
+ u32 *req = (u32 *)buf;
+ int size = 0;
+
+
+ *req = cpu_to_be32(deregister_req->batt_handle);
+ size += sizeof(u32);
+
+ return size;
+}
+
+static int msm_batt_deregister_ret_func(struct msm_rpc_client *batt_client,
+ void *buf, void *data)
+{
+ struct batt_client_deregister_rep *data_ptr, *buf_ptr;
+
+
+
+ data_ptr = (struct batt_client_deregister_rep *)data;
+ buf_ptr = (struct batt_client_deregister_rep *)buf;
+
+ data_ptr->batt_error = be32_to_cpu(buf_ptr->batt_error);
+
+ return 0;
+}
+
+static int msm_batt_deregister(u32 batt_handle)
+{
+ int rc;
+ struct batt_client_deregister_req req;
+ struct batt_client_deregister_rep rep;
+
+
+ req.batt_handle = batt_handle;
+
+ rc = msm_rpc_client_req(msm_batt_info.batt_client,
+ BATTERY_DEREGISTER_CLIENT_PROC,
+ msm_batt_deregister_arg_func, &req,
+ msm_batt_deregister_ret_func, &rep,
+ msecs_to_jiffies(BATT_RPC_TIMEOUT));
+
+ if (rc < 0) {
+ pr_err("%s: FAIL: vbatt deregister. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ if (rep.batt_error != BATTERY_DEREGISTRATION_SUCCESSFUL) {
+ pr_err("%s: vbatt deregistration FAIL. error=%d, handle=%d\n",
+ __func__, rep.batt_error, batt_handle);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int msm_batt_get_charger_type(void)
+{
+ int charger_type = CHARGER_TYPE_NONE;
+
+ charger_type = fsa9480_get_charger_status();
+
+ return charger_type;
+}
+
+#ifdef CONFIG_WIRELESS_CHARGING
+static int msm_batt_get_wireless_status(void)
+{
+ int wc_detect = 0;
+ int charger_type = msm_batt_get_charger_type();
+
+
+ if (charger_type == CHARGER_TYPE_NONE) // no cable inserted
+ {
+ wc_detect = gpio_get_value_cansleep(GPIO_WC_DETECT);
+ return wc_detect;
+ }
+
+ return 0; // plugged
+}
+#endif
+
+static void msm_batt_cable_status_update(void)
+{
+ /* Check charger type and update if changed */
+
+ int charger_type = CHARGER_TYPE_NONE;
+
+ static char *health_text[] = {
+ "Unknown", "Good", "Overheat", "Dead", "Over voltage",
+ "Unspecified failure", "Cold",
+ };
+
+ charger_type = msm_batt_get_charger_type();
+
+#ifdef CONFIG_WIRELESS_CHARGING
+ msm_batt_info.batt_wireless = msm_batt_get_wireless_status();
+
+ if (msm_batt_info.batt_wireless)
+ {
+ charger_type = CHARGER_TYPE_WALL;
+ }
+#endif
+
+ msm_batt_info.charger_type = charger_type;
+ pr_info("[BATT] %s: charger_type = %d (0:none, 1:TA, 2:USB) \n", __func__, charger_type);
+
+ msm_batt_info.batt_full_check = 0;
+ msm_batt_info.batt_recharging = 0;
+
+ if (charger_type != CHARGER_TYPE_NONE) // USB, TA, Wireless
+ {
+ if (charger_type == CHARGER_TYPE_USB_PC)
+ {
+ msm_batt_info.charging_source = USB_CHG;
+ hsusb_chg_connected_ext(USB_CHG_TYPE__SDP);
+ power_supply_changed(&msm_psy_usb);
+ }
+ else // TA and Wireless
+ {
+ msm_batt_info.charging_source = AC_CHG;
+ hsusb_chg_connected_ext(USB_CHG_TYPE__WALLCHARGER);
+ power_supply_changed(&msm_psy_ac);
+ }
+
+ if (msm_batt_info.batt_health != POWER_SUPPLY_HEALTH_GOOD)
+ {
+ pr_info("[BATT] %s: Battery health is %s, stop charging! \n", __func__, health_text[msm_batt_info.batt_health]);
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ msm_batt_chg_en(STOP_CHARGING);
+ }
+ else
+ {
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_CHARGING;
+ msm_batt_chg_en(START_CHARGING);
+ }
+
+ wake_lock(&vbus_wake_lock);
+ }
+ else // No charger
+ {
+ msm_batt_info.charging_source = NO_CHG;
+ msm_batt_info.batt_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ msm_batt_chg_en(STOP_CHARGING);
+ wake_lock_timeout(&vbus_wake_lock, 5 * TIME_UNIT_SECOND);
+ }
+
+ pr_info("[BATT] %s: power_supply_changed !\n", __func__);
+ power_supply_changed(&msm_psy_batt);
+
+ if (msm_batt_unhandled_interrupt)
+ msm_batt_unhandled_interrupt = 0;
+}
+
+static int msm_batt_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ pr_debug("[BATT] %s\n",__func__);
+ del_timer_sync(&msm_batt_info.timer);
+
+ return 0;
+}
+
+static int msm_batt_resume(struct platform_device *pdev)
+{
+ pr_debug("[BATT] %s\n",__func__);
+ queue_work(msm_batt_info.msm_batt_wq, &msm_batt_work);
+ mod_timer(&msm_batt_info.timer, (jiffies + BATT_CHECK_INTERVAL));
+
+ return 0;
+}
+
+int batt_restart(void)
+{
+
+ if (msm_batt_driver_init)
+ {
+ msm_batt_cable_status_update();
+
+ del_timer_sync(&msm_batt_info.timer);
+ queue_work(msm_batt_info.msm_batt_wq, &msm_batt_work);
+ mod_timer(&msm_batt_info.timer, (jiffies + BATT_CHECK_INTERVAL));
+ }
+ else
+ {
+ pr_err("[BATT] %s: Battery driver is not ready !!\n", __func__);
+ msm_batt_unhandled_interrupt = 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(batt_restart);
+
+static int msm_batt_cleanup(void)
+{
+ int rc = 0;
+
+
+ pr_info("[BATT] %s\n", __func__);
+
+ del_timer_sync(&msm_batt_info.timer);
+ msm_batt_remove_attrs(msm_psy_batt.dev);
+ i2c_del_driver(&fg_i2c_driver);
+
+ if (msm_batt_info.batt_handle != INVALID_BATT_HANDLE) {
+
+ rc = msm_batt_deregister(msm_batt_info.batt_handle);
+ if (rc < 0)
+ pr_err("%s: FAIL: msm_batt_deregister. rc=%d\n",
+ __func__, rc);
+ }
+
+ msm_batt_info.batt_handle = INVALID_BATT_HANDLE;
+
+ if (msm_batt_info.batt_client)
+ msm_rpc_unregister_client(msm_batt_info.batt_client);
+
+ if (msm_batt_info.msm_psy_ac)
+ power_supply_unregister(msm_batt_info.msm_psy_ac);
+
+ if (msm_batt_info.msm_psy_usb)
+ power_supply_unregister(msm_batt_info.msm_psy_usb);
+ if (msm_batt_info.msm_psy_batt)
+ power_supply_unregister(msm_batt_info.msm_psy_batt);
+
+ if (msm_batt_info.chg_ep) {
+ rc = msm_rpc_close(msm_batt_info.chg_ep);
+ if (rc < 0) {
+ pr_err("%s: FAIL. msm_rpc_close(chg_ep). rc=%d\n",
+ __func__, rc);
+ }
+ }
+
+#ifdef CONFIG_WIRELESS_CHARGING
+ free_irq(IRQ_WC_DETECT, NULL);
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ if (msm_batt_info.early_suspend.suspend == msm_batt_early_suspend)
+ unregister_early_suspend(&msm_batt_info.early_suspend);
+#endif
+ return rc;
+}
+
+int msm_batt_get_charger_api_version(void)
+{
+ int rc ;
+ struct rpc_reply_hdr *reply;
+
+
+ struct rpc_req_chg_api_ver {
+ struct rpc_request_hdr hdr;
+ u32 more_data;
+ } req_chg_api_ver;
+
+ struct rpc_rep_chg_api_ver {
+ struct rpc_reply_hdr hdr;
+ u32 num_of_chg_api_versions;
+ u32 *chg_api_versions;
+ };
+
+ u32 num_of_versions;
+
+ struct rpc_rep_chg_api_ver *rep_chg_api_ver;
+
+
+ req_chg_api_ver.more_data = cpu_to_be32(1);
+
+ msm_rpc_setup_req(&req_chg_api_ver.hdr, CHG_RPC_PROG, CHG_RPC_VER_1_1,
+ ONCRPC_CHARGER_API_VERSIONS_PROC);
+
+ rc = msm_rpc_write(msm_batt_info.chg_ep, &req_chg_api_ver,
+ sizeof(req_chg_api_ver));
+ if (rc < 0) {
+ pr_err("%s: FAIL: msm_rpc_write. proc=0x%08x, rc=%d\n",
+ __func__, ONCRPC_CHARGER_API_VERSIONS_PROC, rc);
+ return rc;
+ }
+
+ for (;;) {
+ rc = msm_rpc_read(msm_batt_info.chg_ep, (void *) &reply, -1,
+ BATT_RPC_TIMEOUT);
+ if (rc < 0)
+ return rc;
+ if (rc < RPC_REQ_REPLY_COMMON_HEADER_SIZE) {
+ pr_err("%s: LENGTH ERR: msm_rpc_read. rc=%d (<%d)\n",
+ __func__, rc, RPC_REQ_REPLY_COMMON_HEADER_SIZE);
+
+ rc = -EIO;
+ break;
+ }
+ /* we should not get RPC REQ or call packets -- ignore them */
+ if (reply->type == RPC_TYPE_REQ) {
+ pr_err("%s: TYPE ERR: type=%d (!=%d)\n",
+ __func__, reply->type, RPC_TYPE_REQ);
+ kfree(reply);
+ continue;
+ }
+
+ /* If an earlier call timed out, we could get the (no
+ * longer wanted) reply for it. Ignore replies that
+ * we don't expect
+ */
+ if (reply->xid != req_chg_api_ver.hdr.xid) {
+ pr_err("%s: XID ERR: xid=%d (!=%d)\n", __func__,
+ reply->xid, req_chg_api_ver.hdr.xid);
+ kfree(reply);
+ continue;
+ }
+ if (reply->reply_stat != RPCMSG_REPLYSTAT_ACCEPTED) {
+ rc = -EPERM;
+ break;
+ }
+ if (reply->data.acc_hdr.accept_stat !=
+ RPC_ACCEPTSTAT_SUCCESS) {
+ rc = -EINVAL;
+ break;
+ }
+
+ rep_chg_api_ver = (struct rpc_rep_chg_api_ver *)reply;
+
+ num_of_versions =
+ be32_to_cpu(rep_chg_api_ver->num_of_chg_api_versions);
+
+ rep_chg_api_ver->chg_api_versions = (u32 *)
+ ((u8 *) reply + sizeof(struct rpc_reply_hdr) +
+ sizeof(rep_chg_api_ver->num_of_chg_api_versions));
+
+ rc = be32_to_cpu(
+ rep_chg_api_ver->chg_api_versions[num_of_versions - 1]);
+
+ pr_debug("%s: num_of_chg_api_versions = %u. "
+ " The chg api version = 0x%08x\n", __func__,
+ num_of_versions, rc);
+ break;
+ }
+ kfree(reply);
+ return rc;
+}
+
+static int msm_batt_cb_func(struct msm_rpc_client *client,
+ void *buffer, int in_size)
+{
+ int rc = 0;
+ struct rpc_request_hdr *req;
+ u32 procedure;
+ u32 accept_status;
+
+
+ req = (struct rpc_request_hdr *)buffer;
+ procedure = be32_to_cpu(req->procedure);
+
+ switch (procedure) {
+ case BATTERY_CB_TYPE_PROC:
+ accept_status = RPC_ACCEPTSTAT_SUCCESS;
+ break;
+
+ default:
+ accept_status = RPC_ACCEPTSTAT_PROC_UNAVAIL;
+ pr_err("%s: ERROR. procedure (%d) not supported\n",
+ __func__, procedure);
+ break;
+ }
+
+ msm_rpc_start_accepted_reply(msm_batt_info.batt_client,
+ be32_to_cpu(req->xid), accept_status);
+
+ rc = msm_rpc_send_accepted_reply(msm_batt_info.batt_client, 0);
+ if (rc)
+ pr_err("%s: FAIL: sending reply. rc=%d\n", __func__, rc);
+
+ if (accept_status == RPC_ACCEPTSTAT_SUCCESS)
+ {
+ del_timer_sync(&msm_batt_info.timer);
+ queue_work(msm_batt_info.msm_batt_wq, &msm_batt_work);
+ mod_timer(&msm_batt_info.timer, (jiffies + BATT_CHECK_INTERVAL));
+ }
+
+ return rc;
+}
+
+#ifdef CONFIG_WIRELESS_CHARGING
+static irqreturn_t wc_detect_irq_handler(int irq, void *data)
+{
+ int wc_detect = msm_batt_get_wireless_status();
+
+
+ pr_info("[BATT] %s: WC_DETECT = (%d)\n", __func__, wc_detect);
+
+ if (wc_detect == msm_batt_info.batt_wireless) // wireless status is not changed...
+ {
+ return IRQ_HANDLED;
+ }
+
+ batt_restart(); // charger status changed...
+ return IRQ_HANDLED;
+}
+#endif
+
+static void msm_batt_set_charging_start_time(chg_enable_type enable)
+{
+
+ if (enable == START_CHARGING)
+ {
+ charging_start_time = jiffies;
+ }
+ else // STOP_CHARGING
+ {
+ charging_start_time = 0;
+ }
+}
+
+static int msm_batt_is_over_abs_time(void)
+{
+ unsigned int total_time;
+
+
+ if (charging_start_time == 0)
+ {
+ return 0; // not charging
+ }
+
+ if (msm_batt_info.batt_full_check == 1)
+ {
+ total_time = TOTAL_RECHARGING_TIME; // already fully charged... (recharging)
+ }
+ else
+ {
+ total_time = TOTAL_CHARGING_TIME;
+ }
+
+ if (time_after((unsigned long)jiffies, (unsigned long)(charging_start_time + total_time)))
+ {
+ pr_debug("[BATT] %s: abs time is over !! \n", __func__);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#ifdef MAX17043_FUEL_GAUGE
+/* Quick start condition check. */
+static struct fuelgauge_linear_data {
+ u32 min_vcell;
+ u32 slope;
+ u32 y_interception;
+} qstrt_table[2][12] = {
+ { // w/o charger
+ { 450000000, 0, 0 },
+ { 407900000, 2171993, 193731125 },
+ { 389790000, 847027, 324374902 },
+ { 378060000, 602617, 343245771 },
+ { 372020000, 293109, 361124348 },
+ { 368220000, 209554, 364231282 },
+ { 362530000, 596997, 356856383 },
+ { 359070000, 604297, 356792124 },
+ { 354500000, 2679480, 348980813 },
+ { 344820000, 6365513, 341425848 },
+ { 339970000, 9109696, 339974670 },
+ { 100000000, 0, 0 }
+ },
+
+ { // w/charger
+ { 450000000, 0, 0 },
+ { 419270000, 12835, 406438276 },
+ { 418480000, 73645, 349402654 },
+ { 404650000, 45824, 370277069 },
+ { 392800000, 20460, 382744637 },
+ { 387510000, 51008, 375639409 },
+ { 377390000, 298446, 367071455 },
+ { 373320000, 630069, 360004053 },
+ { 363720000, 1231165, 356301531 },
+ { 100000000, 0, 0 },
+ { 100000000, 0, 0 },
+ { 100000000, 0, 0 }
+ },
+};
+
+#define FG_SOC_TOLERANCE 20 // 15
+
+static int check_quick_start(void)
+{
+ unsigned int vcell_raw = 0;
+ int soc_raw = 0, soc_cal = 0;
+ int i, curr_idx = 0;
+ int status = 0;
+ int array_size = 0;
+
+
+ if (msm_batt_get_charger_type() == CHARGER_TYPE_NONE)
+ {
+ status = 0;
+ array_size = 12;
+ pr_debug("[BATT] %s: No charger !\n", __func__);
+ }
+ else
+ {
+ status = 1;
+ array_size = 10;
+ pr_debug("[BATT] %s: charger detected !\n", __func__);
+ }
+
+ /* get vcell. */
+// hyekoseon.yu
+ vcell_raw = fg_read_raw_vcell();
+
+
+
+ /* get soc. */
+ soc_raw = fg_read_raw_soc();
+
+
+
+ /* find range */
+ for (i = 0; i < array_size-1; i++) {
+ if (vcell_raw < qstrt_table[status][i].min_vcell &&
+ vcell_raw >= qstrt_table[status][i+1].min_vcell) {
+ curr_idx = i+1;
+ break;
+ }
+ }
+
+ pr_debug("[BATT] %s: curr_idx = %d (vol=%d)\n", __func__, curr_idx, qstrt_table[status][curr_idx].min_vcell);
+
+ /* calculate assumed soc and compare */
+ if ( (status == 0 && curr_idx > 0 && curr_idx < 11) ||
+ (status == 1 && curr_idx > 0 && curr_idx < 9) ) {
+ int limit_min, limit_max;
+ soc_cal = (int) ((vcell_raw - qstrt_table[status][curr_idx].y_interception) / qstrt_table[status][curr_idx].slope);
+
+ pr_debug("[BATT] %s: soc_cal = %d\n", __func__, soc_cal);
+
+ limit_min = soc_cal - FG_SOC_TOLERANCE;
+ limit_max = soc_cal + FG_SOC_TOLERANCE;
+ if (limit_min < 0)
+ limit_min = 0;
+
+ if (soc_raw > limit_max || soc_raw < limit_min) {
+// hsusb_chg_vbus_draw_ext(0);
+ fg_reset_soc();
+ pr_info("\n[BATT] %s: QUICK START (reset_soc)!!! \n\n", __func__);
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int msm_batt_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_psy_batt_pdata *pdata = pdev->dev.platform_data;
+
+
+ if (pdev->id != -1) {
+ dev_err(&pdev->dev,
+ "%s: MSM chipsets Can only support one"
+ " battery ", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->avail_chg_sources & AC_CHG) {
+ rc = power_supply_register(&pdev->dev, &msm_psy_ac);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "%s: power_supply_register failed"
+ " rc = %d\n", __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+ msm_batt_info.msm_psy_ac = &msm_psy_ac;
+ msm_batt_info.avail_chg_sources |= AC_CHG;
+ }
+
+ if (pdata->avail_chg_sources & USB_CHG) {
+ rc = power_supply_register(&pdev->dev, &msm_psy_usb);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "%s: power_supply_register failed"
+ " rc = %d\n", __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+ msm_batt_info.msm_psy_usb = &msm_psy_usb;
+ msm_batt_info.avail_chg_sources |= USB_CHG;
+ }
+
+ if (!msm_batt_info.msm_psy_ac && !msm_batt_info.msm_psy_usb) {
+
+ dev_err(&pdev->dev,
+ "%s: No external Power supply(AC or USB)"
+ "is avilable\n", __func__);
+ msm_batt_cleanup();
+ return -ENODEV;
+ }
+
+ msm_batt_info.voltage_max_design = pdata->voltage_max_design;
+ msm_batt_info.voltage_min_design = pdata->voltage_min_design;
+ msm_batt_info.batt_technology = pdata->batt_technology;
+
+ if (!msm_batt_info.voltage_min_design)
+ msm_batt_info.voltage_min_design = BATTERY_LOW;
+ if (!msm_batt_info.voltage_max_design)
+ msm_batt_info.voltage_max_design = BATTERY_HIGH;
+ if (msm_batt_info.batt_technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
+ msm_batt_info.batt_technology = POWER_SUPPLY_TECHNOLOGY_LION;
+
+ rc = power_supply_register(&pdev->dev, &msm_psy_batt);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s: power_supply_register failed"
+ " rc=%d\n", __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+ msm_batt_info.msm_psy_batt = &msm_psy_batt;
+
+ rc = msm_batt_register(BATTERY_LOW, BATTERY_ALL_ACTIVITY,
+ BATTERY_CB_ID_ALL_ACTIV, BATTERY_ALL_ACTIVITY);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "%s: msm_batt_register failed rc = %d\n", __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+
+ rc = msm_batt_enable_filter(VBATT_FILTER);
+
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "%s: msm_batt_enable_filter failed rc = %d\n",
+ __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+
+ msm_batt_create_attrs(msm_psy_batt.dev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ msm_batt_info.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
+ msm_batt_info.early_suspend.suspend = msm_batt_early_suspend;
+ msm_batt_info.early_suspend.resume = msm_batt_late_resume;
+ register_early_suspend(&msm_batt_info.early_suspend);
+#endif
+
+ setup_timer(&msm_batt_info.timer, batt_timeover, 0);
+ mod_timer(&msm_batt_info.timer, (jiffies + BATT_CHECK_INTERVAL));
+
+ wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_wake_lock");
+
+#ifdef CONFIG_WIRELESS_CHARGING
+ set_irq_type(IRQ_WC_DETECT, IRQ_TYPE_EDGE_BOTH);
+
+ if (request_threaded_irq(IRQ_WC_DETECT, NULL,
+ wc_detect_irq_handler,
+ IRQF_ONESHOT|(IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING),
+ "WC_DETECT", NULL)) {
+ free_irq(IRQ_WC_DETECT, NULL);
+ pr_err("BATT: irq handler registration failed....\n");
+ }
+#endif
+
+#ifdef CONFIG_MAX17043_FUEL_GAUGE
+
+ if (i2c_add_driver(&fg_i2c_driver))
+ {
+ printk("%s: Can't add max17043 fuel gauge i2c drv\n", __func__);
+ pr_err("%s: Can't add max17043 fuel gauge i2c drv\n", __func__);
+ }
+
+ //check_quick_start();
+
+ if (is_attached)
+ {
+ msm_batt_info.batt_capacity = get_level_from_fuelgauge();
+ msm_batt_info.battery_voltage = get_voltage_from_fuelgauge();
+ }
+
+#ifdef MAX17043_FUEL_GAUGE
+ setup_timer(&fg_alert_timer, fg_set_alert_ext, 0);
+ fg_alert_handler = fg_set_alert;
+#endif
+
+#endif
+
+ /* sys fs */
+ jig_class = class_create(THIS_MODULE, "jig");
+ if (IS_ERR(jig_class))
+ pr_err("Failed to create class(jig)!\n");
+
+ jig_dev = device_create(jig_class, NULL, 0, NULL, "jig");
+ if (IS_ERR(jig_dev))
+ pr_err("Failed to create device(jig)!\n");
+
+ if (device_create_file(jig_dev, &dev_attr_jig) < 0)
+ pr_err("Failed to create device file(%s)!\n", dev_attr_jig.attr.name);
+ /* sys fs */
+
+ msm_batt_driver_init = 1;
+
+ //Need to check init connect check!
+ msm_batt_cable_status_update();
+
+ pr_debug("[BATT] %s : success!\n", __func__);
+
+ return 0;
+}
+
+static int msm_batt_remove(struct platform_device *pdev)
+{
+ int rc;
+ rc = msm_batt_cleanup();
+
+ wake_lock_destroy(&vbus_wake_lock);
+
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "%s: msm_batt_cleanup failed rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void msm_batt_shutdown(struct platform_device *pdev)
+{
+ del_timer_sync(&msm_batt_info.timer);
+}
+
+static const struct dev_pm_ops msm_bat_pm_ops = {
+ .suspend = msm_batt_suspend,
+ .resume = msm_batt_resume,
+};
+
+static struct platform_driver msm_batt_driver = {
+ .probe = msm_batt_probe,
+ .remove = msm_batt_remove,
+ .driver = {
+ .name = "ariesve-battery",
+ .shutdown = msm_batt_shutdown,
+ .pm = &msm_bat_pm_ops,
+ },
+};
+
+static int msm_batt_init_rpc(void)
+{
+ int rc;
+
+
+ msm_batt_info.msm_batt_wq =
+ create_singlethread_workqueue("msm_battery");
+ if (!msm_batt_info.msm_batt_wq) {
+ printk(KERN_ERR "%s: create workque failed \n", __func__);
+ return -ENOMEM;
+ }
+
+ msm_batt_info.chg_ep =
+ msm_rpc_connect_compatible(CHG_RPC_PROG, CHG_RPC_VER_4_1, 0);
+ msm_batt_info.chg_api_version = CHG_RPC_VER_4_1;
+ if (msm_batt_info.chg_ep == NULL) {
+ pr_err("%s: rpc connect CHG_RPC_PROG = NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ if (IS_ERR(msm_batt_info.chg_ep)) {
+ msm_batt_info.chg_ep = msm_rpc_connect_compatible(
+ CHG_RPC_PROG, CHG_RPC_VER_3_1, 0);
+ msm_batt_info.chg_api_version = CHG_RPC_VER_3_1;
+ }
+ if (IS_ERR(msm_batt_info.chg_ep)) {
+ msm_batt_info.chg_ep = msm_rpc_connect_compatible(
+ CHG_RPC_PROG, CHG_RPC_VER_1_1, 0);
+ msm_batt_info.chg_api_version = CHG_RPC_VER_1_1;
+ }
+ if (IS_ERR(msm_batt_info.chg_ep)) {
+ msm_batt_info.chg_ep = msm_rpc_connect_compatible(
+ CHG_RPC_PROG, CHG_RPC_VER_1_3, 0);
+ msm_batt_info.chg_api_version = CHG_RPC_VER_1_3;
+ }
+ if (IS_ERR(msm_batt_info.chg_ep)) {
+ msm_batt_info.chg_ep = msm_rpc_connect_compatible(
+ CHG_RPC_PROG, CHG_RPC_VER_2_2, 0);
+ msm_batt_info.chg_api_version = CHG_RPC_VER_2_2;
+ }
+ if (IS_ERR(msm_batt_info.chg_ep)) {
+ rc = PTR_ERR(msm_batt_info.chg_ep);
+ pr_err("%s: FAIL: rpc connect for CHG_RPC_PROG. rc=%d\n",
+ __func__, rc);
+ msm_batt_info.chg_ep = NULL;
+ return rc;
+ }
+
+ /* Get the real 1.x version */
+ if (msm_batt_info.chg_api_version == CHG_RPC_VER_1_1)
+ msm_batt_info.chg_api_version =
+ msm_batt_get_charger_api_version();
+
+ /* Fall back to 1.1 for default */
+ if (msm_batt_info.chg_api_version < 0)
+ msm_batt_info.chg_api_version = CHG_RPC_VER_1_1;
+ msm_batt_info.batt_api_version = BATTERY_RPC_VER_4_1;
+
+ msm_batt_info.batt_client =
+ msm_rpc_register_client("battery", BATTERY_RPC_PROG,
+ BATTERY_RPC_VER_4_1,
+ 1, msm_batt_cb_func);
+
+ if (msm_batt_info.batt_client == NULL) {
+ pr_err("%s: FAIL: rpc_register_client. batt_client=NULL\n",
+ __func__);
+ return -ENODEV;
+ }
+ if (IS_ERR(msm_batt_info.batt_client)) {
+ msm_batt_info.batt_client =
+ msm_rpc_register_client("battery", BATTERY_RPC_PROG,
+ BATTERY_RPC_VER_1_1,
+ 1, msm_batt_cb_func);
+ msm_batt_info.batt_api_version = BATTERY_RPC_VER_1_1;
+ }
+ if (IS_ERR(msm_batt_info.batt_client)) {
+ msm_batt_info.batt_client =
+ msm_rpc_register_client("battery", BATTERY_RPC_PROG,
+ BATTERY_RPC_VER_2_1,
+ 1, msm_batt_cb_func);
+ msm_batt_info.batt_api_version = BATTERY_RPC_VER_2_1;
+ }
+
+ if (IS_ERR(msm_batt_info.batt_client)) {
+ msm_batt_info.batt_client =
+ msm_rpc_register_client("battery", BATTERY_RPC_PROG,
+ BATTERY_RPC_VER_5_1,
+ 1, msm_batt_cb_func);
+ msm_batt_info.batt_api_version = BATTERY_RPC_VER_5_1;
+ }
+ if (IS_ERR(msm_batt_info.batt_client)) {
+ rc = PTR_ERR(msm_batt_info.batt_client);
+ pr_err("%s: ERROR: rpc_register_client: rc = %d\n ",
+ __func__, rc);
+ msm_batt_info.batt_client = NULL;
+ return rc;
+ }
+
+ rc = platform_driver_register(&msm_batt_driver);
+
+ if (rc < 0)
+ pr_err("%s: FAIL: platform_driver_register. rc = %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int __init msm_batt_init(void)
+{
+ int rc;
+
+
+ rc = msm_batt_init_rpc();
+
+ if (rc < 0) {
+ pr_err("%s: FAIL: msm_batt_init_rpc. rc=%d\n", __func__, rc);
+ msm_batt_cleanup();
+ return rc;
+ }
+
+ pr_info("%s: Charger/Battery = 0x%08x/0x%08x (RPC version)\n",
+ __func__, msm_batt_info.chg_api_version,
+ msm_batt_info.batt_api_version);
+
+ //Check jig status
+ if(fsa9480_get_jig_status())
+ batt_jig_on_status = 1;
+ else
+ batt_jig_on_status = 0;
+
+ return 0;
+}
+
+static void __exit msm_batt_exit(void)
+{
+
+ platform_driver_unregister(&msm_batt_driver);
+}
+
+module_init(msm_batt_init);
+module_exit(msm_batt_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Kiran Kandi, Qualcomm Innovation Center, Inc.");
+MODULE_DESCRIPTION("Battery driver for Qualcomm MSM chipsets.");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:ariesve_battery");
diff --git a/drivers/power/fuelgauge_max17043.c b/drivers/power/fuelgauge_max17043.c
new file mode 100644
index 0000000..97d4fc1
--- /dev/null
+++ b/drivers/power/fuelgauge_max17043.c
@@ -0,0 +1,434 @@
+/*
+ *
+ * Copyright (C) 2009 SAMSUNG ELECTRONICS.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Slave address */
+#define MAX17040_SLAVE_ADDR 0x6D
+
+/* Register address */
+#define VCELL0_REG 0x02
+#define VCELL1_REG 0x03
+#define SOC0_REG 0x04
+#define SOC1_REG 0x05
+#define MODE0_REG 0x06
+#define MODE1_REG 0x07
+#define RCOMP0_REG 0x0C
+#define RCOMP1_REG 0x0D
+#define CMD0_REG 0xFE
+#define CMD1_REG 0xFF
+
+#include <linux/slab.h>
+
+extern bool power_down;
+
+static struct i2c_driver fg_i2c_driver;
+struct fg_i2c_chip {
+ struct i2c_client *client;
+};
+static struct fg_i2c_chip *fg_max17043 = NULL;
+
+static int is_reset_soc = 0;
+static int is_attached = 0;
+
+#ifdef MAX17043_FUEL_GAUGE
+static int is_alert = 0; // ALARM_INT
+#endif
+
+static int fg_i2c_read(struct i2c_client *client, u8 reg, u8 *data)
+{
+ int ret;
+ u8 buf[1];
+ struct i2c_msg msg[2];
+
+
+ buf[0] = reg;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = buf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = buf;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret != 2)
+ return -EIO;
+
+ *data = buf[0];
+
+ return 0;
+}
+
+static int fg_i2c_write(struct i2c_client *client, u8 reg, u8 *data)
+{
+ int ret;
+ u8 buf[3];
+ struct i2c_msg msg[1];
+
+
+ buf[0] = reg;
+ buf[1] = *data;
+ buf[2] = *(data + 1);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 3;
+ msg[0].buf = buf;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1)
+ return -EIO;
+
+ return 0;
+}
+
+// hyeokseon.yu
+unsigned int fg_read_vcell(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 data[2];
+ u32 vcell = 0;
+
+
+ if (!client)
+ return -1;
+
+ if (fg_i2c_read(client, VCELL0_REG, &data[0]) < 0) {
+ pr_err("%s: Failed to read VCELL0\n", __func__);
+ return -1;
+ }
+ if (fg_i2c_read(client, VCELL1_REG, &data[1]) < 0) {
+ pr_err("%s: Failed to read VCELL1\n", __func__);
+ return -1;
+ }
+
+#if defined(CONFIG_BATT_MICROVOLT_UNIT)
+ vcell = (((data[0] << 4) & 0xFF0) | ((data[1] >> 4) & 0xF)) * 1250;
+#else
+ vcell = ((((data[0] << 4) & 0xFF0) | ((data[1] >> 4) & 0xF)) * 125)/100;
+#endif
+
+ if(!power_down)
+ pr_debug("%s: VCELL=%d\n", __func__, vcell);
+
+ return vcell;
+}
+
+// hyeokseon.yu
+unsigned int fg_read_soc(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 data[2];
+ int FGPureSOC = 0;
+ int FGAdjustSOC = 0;
+ int FGSOC = 0;
+
+ if (!client)
+ return -1;
+
+ if (fg_i2c_read(client, SOC0_REG, &data[0]) < 0) {
+ pr_err("%s: Failed to read SOC0\n", __func__);
+ return -1;
+ }
+ if (fg_i2c_read(client, SOC1_REG, &data[1]) < 0) {
+ pr_err("%s: Failed to read SOC1\n", __func__);
+ return -1;
+ }
+
+ if (is_reset_soc) {
+ pr_info("%s: Reseting SOC\n", __func__);
+ return -1;
+ }
+
+ /*Adjusted SOC(Ancora)
+ **RCOMP : B0h, FULL : 96.7, EMPTY : 0.0
+ **Adjusted SOC(Aries VE)
+ **RCOMP : D0h, FULL : 97.7, EMPTY : 0.4
+ **Adj_soc = (SOC%-EMPTY)/(FULL-EMPTY)*100
+ */
+
+ // calculating soc
+ FGPureSOC = data[0]*100+((data[1]*100)/256);
+
+ // hsil for get Adjusted SOC%
+ if(FGPureSOC >= 0)
+#ifdef CONFIG_MACH_ARIESVE
+ FGAdjustSOC = ((FGPureSOC*10000)-40)/9730;
+#else
+ FGAdjustSOC = ((FGPureSOC*10000)-0)/9670;
+#endif
+ else
+ FGAdjustSOC = 0;
+
+ // rounding off and Changing to percentage.
+ FGSOC=FGAdjustSOC/100;
+
+#ifdef CONFIG_MACH_ARIESVE
+ if(FGAdjustSOC%100 >= 50)
+#else
+ if(FGAdjustSOC%100 >= 50 && FGSOC > 1)
+#endif
+ FGSOC+=1;
+
+ if(FGSOC>=100)
+ FGSOC=100;
+
+ if (FGSOC < 0)
+ FGSOC = 0;
+
+ if(!power_down)
+ printk("[MAX17043] FGPureSOC = %d (%d.%d)\tFGAdjustSOC = %d\tFGSOC = %d\n", FGPureSOC, data[0], (data[1]*100)/256, FGAdjustSOC, FGSOC);
+
+
+ return FGSOC;
+}
+
+// hyeokseon.yu
+unsigned int fg_read_raw_vcell(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 data[2];
+ u32 vcell = 0;
+
+ if (!client)
+ return -1;
+
+ if (fg_i2c_read(client, VCELL0_REG, &data[0]) < 0) {
+ pr_err("%s: Failed to read VCELL0\n", __func__);
+ return -1;
+ }
+ if (fg_i2c_read(client, VCELL1_REG, &data[1]) < 0) {
+ pr_err("%s: Failed to read VCELL1\n", __func__);
+ return -1;
+ }
+
+ vcell = data[0] << 8 | data[1];
+ vcell = (vcell >> 4) * 125 * 1000;
+
+ printk("SEXYKYU %s: VCELL=%d\n", __func__, vcell);
+
+ return vcell;
+}
+
+unsigned int fg_read_raw_soc(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 data[2];
+
+ if (!client)
+ return -1;
+
+ if (fg_i2c_read(client, SOC0_REG, &data[0]) < 0) {
+ pr_err("%s: Failed to read SOC0\n", __func__);
+ return -1;
+ }
+ if (fg_i2c_read(client, SOC1_REG, &data[1]) < 0) {
+ pr_err("%s: Failed to read SOC1\n", __func__);
+ return -1;
+ }
+
+ if (data[0] < 0) data[0] = 0;
+ if (data[0] > 100) data[0] = 100;
+
+ pr_debug("%s: SOC [0]=%d [1]=%d\n", __func__, data[0], data[1]);
+
+ if (is_reset_soc) {
+ pr_info("%s: Reseting SOC\n", __func__);
+ return -1;
+ } else {
+ return data[0];
+ }
+}
+
+// hyeokseon.yu
+unsigned int fg_reset_soc(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 rst_cmd[2];
+ s32 ret = 0;
+
+
+ if (!client)
+ return -1;
+
+ is_reset_soc = 1;
+ /* Quick-start */
+ rst_cmd[0] = 0x40;
+ rst_cmd[1] = 0x00;
+
+ ret = fg_i2c_write(client, MODE0_REG, rst_cmd);
+ if (ret)
+ pr_err("[BATT] %s: failed reset SOC(%d)\n", __func__, ret);
+
+ msleep(500);
+ is_reset_soc = 0;
+ return ret;
+}
+
+// hyeokseon.yu
+void fuel_gauge_rcomp(void)
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 rst_cmd[2];
+ s32 ret = 0;
+
+
+ if (!client)
+ return ;
+#if defined(CONFIG_MACH_ARIESVE) || defined(CONFIG_MACH_APACHE)
+ rst_cmd[0] = 0xC0; /* MAXIM recommend */
+#else
+ rst_cmd[0] = 0xB0;
+#endif
+
+#ifdef MAX17043_FUEL_GAUGE
+ rst_cmd[1] = 0x1F;
+#else
+ rst_cmd[1] = 0x00;
+#endif
+
+ ret = fg_i2c_write(client, RCOMP0_REG, rst_cmd);
+ if (ret)
+ pr_err("[BATT] %s: failed fuel_gauge_rcomp(%d)\n", __func__, ret);
+
+ //msleep(500);
+}
+
+#ifdef MAX17043_FUEL_GAUGE
+int (*fg_alert_handler)(int) = NULL;
+static irqreturn_t fg_interrupt_handler(int irq, void *data) // ALARM_INT
+{
+ struct i2c_client *client = fg_max17043->client;
+ u8 rst_cmd[2];
+ int ret = 0;
+
+ if (!client)
+ return IRQ_HANDLED;
+
+ rst_cmd[0] = 0x00;
+ rst_cmd[1] = 0x00;
+
+ if (fg_i2c_read(client, RCOMP0_REG, &rst_cmd[0]) < 0)
+ {
+ pr_err("[BATT] %s failed!\n", __func__);
+ return IRQ_HANDLED;
+ }
+ if (fg_i2c_read(client, RCOMP1_REG, &rst_cmd[1]) < 0)
+ {
+ pr_err("[BATT] %s failed!\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+#ifdef DEBUG
+ pr_info("\n-----------------------------------------------------\n");
+ pr_info(" << %s (vcell:%d, soc:%d, rcomp:0x%x,0x%x) >> \n", __func__, fg_read_vcell(), fg_read_soc(), rst_cmd[0], rst_cmd[1]);
+ pr_info("-----------------------------------------------------\n\n");
+#endif
+
+ if(fg_alert_handler) {
+ ret = (*fg_alert_handler)(1);
+
+ if (ret)
+ pr_info("[BATT]: %s: low battery alert, ready to power down (0x%x, 0x%x)\n", __func__, rst_cmd[0], rst_cmd[1]);
+ else
+ // ignore alert
+ pr_info("[BATT] %s: Ignore low battery alert during charging... \n", __func__);
+ }
+
+ // Clear ALRT bit to prevent another low battery interrupt...
+ rst_cmd[1] = rst_cmd[1] & 0xDF;
+
+#ifdef DEBUG
+ pr_info("[FG] %s: clear the bit = 0x%x, 0x%x \n", __func__, rst_cmd[0], rst_cmd[1]);
+#endif
+
+ if (fg_i2c_write(client, RCOMP0_REG, rst_cmd))
+ pr_err("[BATT] %s: failed write rcomp\n", __func__);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int fg_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+
+ if (fg_max17043 == NULL ) {
+ fg_max17043 = kzalloc(sizeof(struct fg_i2c_chip), GFP_KERNEL);
+ if (fg_max17043 == NULL ) {
+ return -ENOMEM;
+ }
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+ return -EIO;
+
+ fg_max17043->client = client;
+
+ i2c_set_clientdata(client, fg_max17043);
+
+ fuel_gauge_rcomp();
+
+#ifdef MAX17043_FUEL_GAUGE
+ if (request_threaded_irq(client->irq, NULL,
+ fg_interrupt_handler,
+ IRQF_ONESHOT|IRQF_TRIGGER_FALLING, "ALARM_INT", client))
+ {
+ free_irq(client->irq, NULL);
+ pr_err("[BATT] fg_interrupt_handler can't register the handler! and passing....\n");
+ }
+#endif
+
+ is_attached = 1;
+
+ pr_debug("[BATT] %s : success!\n", __func__);
+ return 0;
+}
+
+static int fg_i2c_remove(struct i2c_client *client)
+{
+ struct max17040_chip *chip = i2c_get_clientdata(client);
+
+
+ pr_info("[BATT] %s\n", __func__);
+
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ fg_max17043->client = NULL;
+ return 0;
+}
+
+#define fg_i2c_suspend NULL
+#define fg_i2c_resume NULL
+
+
+static const struct i2c_device_id fg_i2c_id[] = {
+ { "fuelgauge_max17043", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max17040_id);
+
+static struct i2c_driver fg_i2c_driver = {
+ .driver = {
+ .name = "fuelgauge_max17043",
+ },
+ .probe = fg_i2c_probe,
+ .remove = fg_i2c_remove,
+ .suspend = fg_i2c_suspend,
+ .resume = fg_i2c_resume,
+ .id_table = fg_i2c_id,
+};
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 29178f7..3d81e0d 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -33,7 +33,7 @@
#define POWER_SUPPLY_ATTR(_name) \
{ \
- .attr = { .name = #_name }, \
+ .attr = { .name = #_name, .mode = 0444 }, \
.show = power_supply_show_property, \
.store = power_supply_store_property, \
}
@@ -104,6 +104,10 @@ static ssize_t power_supply_show_property(struct device *dev,
return sprintf(buf, "%s\n", scope_text[value.intval]);
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
return sprintf(buf, "%s\n", value.strval);
+ else if (off >= POWER_SUPPLY_PROP_BATT_FULL)
+ return sprintf(buf, "%d\n", value.intval);
+ else if (off >= POWER_SUPPLY_PROP_BATT_TYPE)
+ return sprintf(buf, "SDI_SDI\n");
return sprintf(buf, "%d\n", value.intval);
}
@@ -141,7 +145,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(online),
POWER_SUPPLY_ATTR(authentic),
POWER_SUPPLY_ATTR(technology),
- POWER_SUPPLY_ATTR(cycle_count),
+ /* POWER_SUPPLY_ATTR(cycle_count), */
POWER_SUPPLY_ATTR(voltage_max),
POWER_SUPPLY_ATTR(voltage_min),
POWER_SUPPLY_ATTR(voltage_max_design),
@@ -183,6 +187,17 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(temp_ambient),
POWER_SUPPLY_ATTR(temp_ambient_alert_min),
POWER_SUPPLY_ATTR(temp_ambient_alert_max),
+ POWER_SUPPLY_ATTR(batt_temp),
+ POWER_SUPPLY_ATTR(batt_temp_adc),
+ POWER_SUPPLY_ATTR(batt_vol),
+ POWER_SUPPLY_ATTR(batt_vol_adc),
+ POWER_SUPPLY_ATTR(batt_vf_adc),
+ POWER_SUPPLY_ATTR(batt_vol_adc_aver),
+ POWER_SUPPLY_ATTR(batt_temp_adc_aver),
+ POWER_SUPPLY_ATTR(batt_vol_aver),
+ POWER_SUPPLY_ATTR(batt_temp_aver),
+ POWER_SUPPLY_ATTR(batt_type),
+ POWER_SUPPLY_ATTR(batt_full_check),
POWER_SUPPLY_ATTR(time_to_empty_now),
POWER_SUPPLY_ATTR(time_to_empty_avg),
POWER_SUPPLY_ATTR(time_to_full_now),
diff --git a/include/linux/earlysuspend.h b/include/linux/earlysuspend.h
new file mode 100644
index 0000000..8343b81
--- /dev/null
+++ b/include/linux/earlysuspend.h
@@ -0,0 +1,56 @@
+/* include/linux/earlysuspend.h
+ *
+ * Copyright (C) 2007-2008 Google, 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.
+ *
+ */
+
+#ifndef _LINUX_EARLYSUSPEND_H
+#define _LINUX_EARLYSUSPEND_H
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/list.h>
+#endif
+
+/* The early_suspend structure defines suspend and resume hooks to be called
+ * when the user visible sleep state of the system changes, and a level to
+ * control the order. They can be used to turn off the screen and input
+ * devices that are not used for wakeup.
+ * Suspend handlers are called in low to high level order, resume handlers are
+ * called in the opposite order. If, when calling register_early_suspend,
+ * the suspend handlers have already been called without a matching call to the
+ * resume handlers, the suspend handler will be called directly from
+ * register_early_suspend. This direct call can violate the normal level order.
+ */
+enum {
+ EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
+ EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
+ EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
+};
+struct early_suspend {
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct list_head link;
+ int level;
+ void (*suspend)(struct early_suspend *h);
+ void (*resume)(struct early_suspend *h);
+#endif
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void register_early_suspend(struct early_suspend *handler);
+void unregister_early_suspend(struct early_suspend *handler);
+#else
+#define register_early_suspend(handler) do { } while (0)
+#define unregister_early_suspend(handler) do { } while (0)
+#endif
+
+#endif
+
diff --git a/include/linux/leds-pmic8058.h b/include/linux/leds-pmic8058.h
new file mode 100644
index 0000000..cbfde9f
--- /dev/null
+++ b/include/linux/leds-pmic8058.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#ifndef __LEDS_PMIC8058_H__
+#define __LEDS_PMIC8058_H__
+
+enum pmic8058_leds {
+ PMIC8058_ID_LED_KB_LIGHT = 1,
+ PMIC8058_ID_LED_0,
+ PMIC8058_ID_LED_1,
+ PMIC8058_ID_LED_2,
+ PMIC8058_ID_FLASH_LED_0,
+ PMIC8058_ID_FLASH_LED_1,
+};
+
+struct pmic8058_led {
+ const char *name;
+ const char *default_trigger;
+ unsigned max_brightness;
+ int id;
+};
+
+struct pmic8058_leds_platform_data {
+ int num_leds;
+ struct pmic8058_led *leds;
+};
+
+int pm8058_set_flash_led_current(enum pmic8058_leds id, unsigned mA);
+int pm8058_set_led_current(enum pmic8058_leds id, unsigned mA);
+
+#endif /* __LEDS_PMIC8058_H__ */
diff --git a/include/linux/mfd/pm8xxx/batt-alarm.h b/include/linux/mfd/pm8xxx/batt-alarm.h
new file mode 100644
index 0000000..f10715d
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/batt-alarm.h
@@ -0,0 +1,201 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+/*
+ * Qualcomm PMIC PM8xxx Battery Alarm driver
+ *
+ */
+#ifndef __MFD_PM8XXX_BATT_ALARM_H__
+#define __MFD_PM8XXX_BATT_ALARM_H__
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/notifier.h>
+
+#define PM8XXX_BATT_ALARM_DEV_NAME "pm8xxx-batt-alarm"
+
+/**
+ * enum pm8xxx_batt_alarm_core_data - PMIC core specific core passed into the
+ * batter alarm driver as platform data
+ * @irq_name:
+ * @reg_addr_batt_alarm_threshold: PMIC threshold register address
+ * @reg_addr_batt_alarm_ctrl1: PMIC control 1 register address
+ * @reg_addr_batt_alarm_ctrl2: PMIC control 2 register address
+ * @reg_addr_batt_alarm_pwm_ctrl: PMIC PWM control register address
+ */
+struct pm8xxx_batt_alarm_core_data {
+ char *irq_name;
+ u16 reg_addr_threshold;
+ u16 reg_addr_ctrl1;
+ u16 reg_addr_ctrl2;
+ u16 reg_addr_pwm_ctrl;
+};
+
+/**
+ * enum pm8xxx_batt_alarm_comparator - battery alarm comparator ID values
+ */
+enum pm8xxx_batt_alarm_comparator {
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
+};
+
+/**
+ * enum pm8xxx_batt_alarm_hold_time - hold time required for out of range
+ * battery voltage needed to trigger a status change. Enum names denote
+ * hold time in milliseconds.
+ */
+enum pm8xxx_batt_alarm_hold_time {
+ PM8XXX_BATT_ALARM_HOLD_TIME_0p125_MS = 0,
+ PM8XXX_BATT_ALARM_HOLD_TIME_0p25_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_0p5_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_1_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_2_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_4_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_8_MS,
+ PM8XXX_BATT_ALARM_HOLD_TIME_16_MS,
+};
+
+/*
+ * Bits that are set in the return value of pm8xxx_batt_alarm_status_read
+ * to indicate crossing of the upper or lower threshold.
+ */
+#define PM8XXX_BATT_ALARM_STATUS_BELOW_LOWER BIT(0)
+#define PM8XXX_BATT_ALARM_STATUS_ABOVE_UPPER BIT(1)
+
+#if defined(CONFIG_MFD_PM8XXX_BATT_ALARM) \
+ || defined(CONFIG_MFD_PM8XXX_BATT_ALARM_MODULE)
+
+/**
+ * pm8xxx_batt_alarm_enable - enable one of the battery voltage threshold
+ * comparators
+ * @comparator: selects which comparator to enable
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_enable(enum pm8xxx_batt_alarm_comparator comparator);
+
+/**
+ * pm8xxx_batt_alarm_disable - disable one of the battery voltage threshold
+ * comparators
+ * @comparator: selects which comparator to disable
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_disable(enum pm8xxx_batt_alarm_comparator comparator);
+
+
+/**
+ * pm8xxx_batt_alarm_threshold_set - set the lower and upper alarm thresholds
+ * @comparator: selects which comparator to set the threshold of
+ * @threshold_mV: battery voltage threshold in millivolts
+ * set points = 2500-5675 mV in 25 mV steps
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_threshold_set(
+ enum pm8xxx_batt_alarm_comparator comparator, int threshold_mV);
+
+/**
+ * pm8xxx_batt_alarm_status_read - get status of both threshold comparators
+ *
+ * RETURNS: < 0 = error
+ * 0 = battery voltage ok
+ * BIT(0) set = battery voltage below lower threshold
+ * BIT(1) set = battery voltage above upper threshold
+ */
+int pm8xxx_batt_alarm_status_read(void);
+
+/**
+ * pm8xxx_batt_alarm_register_notifier - register a notifier to run when a
+ * battery voltage change interrupt fires
+ * @nb: notifier block containing callback function to register
+ *
+ * nb->notifier_call must point to a function of this form -
+ * int (*notifier_call)(struct notifier_block *nb, unsigned long status,
+ * void *unused);
+ * "status" will receive the battery alarm status; "unused" will be NULL.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_register_notifier(struct notifier_block *nb);
+
+/**
+ * pm8xxx_batt_alarm_unregister_notifier - unregister a notifier that is run
+ * when a battery voltage change interrupt fires
+ * @nb: notifier block containing callback function to unregister
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_unregister_notifier(struct notifier_block *nb);
+
+/**
+ * pm8xxx_batt_alarm_hold_time_set - set hold time of interrupt output *
+ * @hold_time: amount of time that battery voltage must remain outside of the
+ * threshold range before the battery alarm interrupt triggers
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_hold_time_set(enum pm8xxx_batt_alarm_hold_time hold_time);
+
+/**
+ * pm8xxx_batt_alarm_pwm_rate_set - set battery alarm update rate *
+ * @use_pwm: 1 = use PWM update rate, 0 = comparators always active
+ * @clock_scaler: PWM clock scaler = 2 to 9
+ * @clock_divider: PWM clock divider = 2 to 8
+ *
+ * This function sets the rate at which the battery alarm module enables
+ * the threshold comparators. The rate is determined by the following equation:
+ *
+ * f_update = (1024 Hz) / (clock_divider * (2 ^ clock_scaler))
+ *
+ * Thus, the update rate can range from 0.25 Hz to 128 Hz.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler,
+ int clock_divider);
+#else
+
+static inline int
+pm8xxx_batt_alarm_enable(enum pm8xxx_batt_alarm_comparator comparator)
+{ return -ENODEV; }
+
+static inline int
+pm8xxx_batt_alarm_disable(enum pm8xxx_batt_alarm_comparator comparator)
+{ return -ENODEV; }
+
+static inline int
+pm8xxx_batt_alarm_threshold_set(enum pm8xxx_batt_alarm_comparator comparator,
+ int threshold_mV)
+{ return -ENODEV; }
+
+static inline int pm8xxx_batt_alarm_status_read(void)
+{ return -ENODEV; }
+
+static inline int pm8xxx_batt_alarm_register_notifier(struct notifier_block *nb)
+{ return -ENODEV; }
+
+static inline int
+pm8xxx_batt_alarm_unregister_notifier(struct notifier_block *nb)
+{ return -ENODEV; }
+
+static inline int
+pm8xxx_batt_alarm_hold_time_set(enum pm8xxx_batt_alarm_hold_time hold_time)
+{ return -ENODEV; }
+
+static inline int
+pm8xxx_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler, int clock_divider)
+{ return -ENODEV; }
+
+#endif
+
+
+#endif /* __MFD_PM8XXX_BATT_ALARM_H__ */
diff --git a/include/linux/mfd/pm8xxx/gpio.h b/include/linux/mfd/pm8xxx/gpio.h
new file mode 100644
index 0000000..ccd9c10
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/gpio.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * Qualcomm PMIC8XXX gpio driver header file
+ *
+ */
+
+#ifndef __PM8XXX_GPIO_H
+#define __PM8XXX_GPIO_H
+
+#include <linux/errno.h>
+
+#define PM8XXX_GPIO_DEV_NAME "pm8xxx-gpio"
+
+struct pm8xxx_gpio_core_data {
+ int ngpios;
+};
+
+struct pm8xxx_gpio_platform_data {
+ struct pm8xxx_gpio_core_data gpio_cdata;
+ int gpio_base;
+};
+
+/* GPIO parameters */
+/* direction */
+#define PM_GPIO_DIR_OUT 0x01
+#define PM_GPIO_DIR_IN 0x02
+#define PM_GPIO_DIR_BOTH (PM_GPIO_DIR_OUT | PM_GPIO_DIR_IN)
+
+/* output_buffer */
+#define PM_GPIO_OUT_BUF_OPEN_DRAIN 1
+#define PM_GPIO_OUT_BUF_CMOS 0
+
+/* pull */
+#define PM_GPIO_PULL_UP_30 0
+#define PM_GPIO_PULL_UP_1P5 1
+#define PM_GPIO_PULL_UP_31P5 2
+#define PM_GPIO_PULL_UP_1P5_30 3
+#define PM_GPIO_PULL_DN 4
+#define PM_GPIO_PULL_NO 5
+
+/* vin_sel: Voltage Input Select */
+#define PM_GPIO_VIN_VPH 0 /* 3v ~ 4.4v */
+#define PM_GPIO_VIN_BB 1 /* ~3.3v */
+#define PM_GPIO_VIN_S4 2 /* 1.8v */
+#define PM_GPIO_VIN_L15 3
+#define PM_GPIO_VIN_L4 4
+#define PM_GPIO_VIN_L3 5
+#define PM_GPIO_VIN_L17 6
+
+/* vin_sel: Voltage Input select on PM8058 */
+#define PM8058_GPIO_VIN_VPH 0
+#define PM8058_GPIO_VIN_BB 1
+#define PM8058_GPIO_VIN_S3 2
+#define PM8058_GPIO_VIN_L3 3
+#define PM8058_GPIO_VIN_L7 4
+#define PM8058_GPIO_VIN_L6 5
+#define PM8058_GPIO_VIN_L5 6
+#define PM8058_GPIO_VIN_L2 7
+
+/* vin_sel: Voltage Input Select on PM8038*/
+#define PM8038_GPIO_VIN_VPH 0
+#define PM8038_GPIO_VIN_BB 1
+#define PM8038_GPIO_VIN_L11 2
+#define PM8038_GPIO_VIN_L15 3
+#define PM8038_GPIO_VIN_L4 4
+#define PM8038_GPIO_VIN_L3 5
+#define PM8038_GPIO_VIN_L17 6
+
+/* vin_sel: Voltage Input Select on PM8018*/
+#define PM8018_GPIO_VIN_L4 0
+#define PM8018_GPIO_VIN_L14 1
+#define PM8018_GPIO_VIN_S3 2
+#define PM8018_GPIO_VIN_L6 3
+#define PM8018_GPIO_VIN_L2 4
+#define PM8018_GPIO_VIN_L5 5
+#define PM8018_GPIO_VIN_L8 6
+#define PM8018_GPIO_VIN_VPH 7
+
+/* out_strength */
+#define PM_GPIO_STRENGTH_NO 0
+#define PM_GPIO_STRENGTH_HIGH 1
+#define PM_GPIO_STRENGTH_MED 2
+#define PM_GPIO_STRENGTH_LOW 3
+
+/* function */
+#define PM_GPIO_FUNC_NORMAL 0
+#define PM_GPIO_FUNC_PAIRED 1
+#define PM_GPIO_FUNC_1 2
+#define PM_GPIO_FUNC_2 3
+#define PM_GPIO_DTEST1 4
+#define PM_GPIO_DTEST2 5
+#define PM_GPIO_DTEST3 6
+#define PM_GPIO_DTEST4 7
+
+/**
+ * struct pm_gpio - structure to specify gpio configurtion values
+ * @direction: indicates whether the gpio should be input, output, or
+ * both. Should be of the type PM_GPIO_DIR_*
+ * @output_buffer: indicates gpio should be configured as CMOS or open
+ * drain. Should be of the type PM_GPIO_OUT_BUF_*
+ * @output_value: The gpio output value of the gpio line - 0 or 1
+ * @pull: Indicates whether a pull up or pull down should be
+ * applied. If a pullup is required the current strength
+ * needs to be specified. Current values of 30uA, 1.5uA,
+ * 31.5uA, 1.5uA with 30uA boost are supported. This value
+ * should be one of the PM_GPIO_PULL_*
+ * @vin_sel: specifies the voltage level when the output is set to 1.
+ * For an input gpio specifies the voltage level at which
+ * the input is interpreted as a logical 1.
+ * @out_strength: the amount of current supplied for an output gpio,
+ * should be of the type PM_GPIO_STRENGTH_*
+ * @function: choose alternate function for the gpio. Certain gpios
+ * can be paired (shorted) with each other. Some gpio pin
+ * can act as alternate functions. This parameter should
+ * be of type PM_GPIO_FUNC_*
+ * @inv_int_pol: Invert polarity before feeding the line to the interrupt
+ * module in pmic. This feature will almost be never used
+ * since the pm8xxx interrupt block can detect both edges
+ * and both levels.
+ * @disable_pin: Disable the gpio by configuring it as high impedance.
+ */
+struct pm_gpio {
+ int direction;
+ int output_buffer;
+ int output_value;
+ int pull;
+ int vin_sel;
+ int out_strength;
+ int function;
+ int inv_int_pol;
+ int disable_pin;
+};
+
+#if defined(CONFIG_GPIO_PM8XXX) || defined(CONFIG_GPIO_PM8XXX_MODULE)
+/**
+ * pm8xxx_gpio_config - configure a gpio controlled by a pm8xxx chip
+ * @gpio: gpio number to configure
+ * @param: configuration values
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_gpio_config(int gpio, struct pm_gpio *param);
+#else
+static inline int pm8xxx_gpio_config(int gpio, struct pm_gpio *param)
+{
+ return -ENXIO;
+}
+#endif
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
new file mode 100644
index 0000000..c4b0ea4
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MFD_PM8XXX_MISC_H__
+#define __MFD_PM8XXX_MISC_H__
+
+#include <linux/err.h>
+
+#define PM8XXX_MISC_DEV_NAME "pm8xxx-misc"
+
+/**
+ * struct pm8xxx_misc_platform_data - PM8xxx misc driver platform data
+ * @priority: PMIC prority level in a multi-PMIC system. Lower value means
+ * greater priority. Actions are performed from highest to lowest
+ * priority PMIC.
+ */
+struct pm8xxx_misc_platform_data {
+ int priority;
+};
+
+enum pm8xxx_uart_path_sel {
+ UART_NONE,
+ UART_TX1_RX1,
+ UART_TX2_RX2,
+ UART_TX3_RX3,
+};
+
+enum pm8xxx_coincell_chg_voltage {
+ PM8XXX_COINCELL_VOLTAGE_3p2V = 1,
+ PM8XXX_COINCELL_VOLTAGE_3p1V,
+ PM8XXX_COINCELL_VOLTAGE_3p0V,
+ PM8XXX_COINCELL_VOLTAGE_2p5V = 16
+};
+
+enum pm8xxx_coincell_chg_resistor {
+ PM8XXX_COINCELL_RESISTOR_2100_OHMS,
+ PM8XXX_COINCELL_RESISTOR_1700_OHMS,
+ PM8XXX_COINCELL_RESISTOR_1200_OHMS,
+ PM8XXX_COINCELL_RESISTOR_800_OHMS
+};
+
+enum pm8xxx_coincell_chg_state {
+ PM8XXX_COINCELL_CHG_DISABLE,
+ PM8XXX_COINCELL_CHG_ENABLE
+};
+
+struct pm8xxx_coincell_chg {
+ enum pm8xxx_coincell_chg_state state;
+ enum pm8xxx_coincell_chg_voltage voltage;
+ enum pm8xxx_coincell_chg_resistor resistor;
+};
+
+enum pm8xxx_smpl_delay {
+ PM8XXX_SMPL_DELAY_0p5,
+ PM8XXX_SMPL_DELAY_1p0,
+ PM8XXX_SMPL_DELAY_1p5,
+ PM8XXX_SMPL_DELAY_2p0,
+};
+
+enum pm8xxx_pon_config {
+ PM8XXX_DISABLE_HARD_RESET = 0,
+ PM8XXX_SHUTDOWN_ON_HARD_RESET,
+ PM8XXX_RESTART_ON_HARD_RESET,
+};
+
+enum pm8xxx_aux_clk_id {
+ CLK_MP3_1,
+ CLK_MP3_2,
+};
+
+enum pm8xxx_aux_clk_div {
+ XO_DIV_NONE,
+ XO_DIV_1,
+ XO_DIV_2,
+ XO_DIV_4,
+ XO_DIV_8,
+ XO_DIV_16,
+ XO_DIV_32,
+ XO_DIV_64,
+};
+
+enum pm8xxx_hsed_bias {
+ PM8XXX_HSED_BIAS0,
+ PM8XXX_HSED_BIAS1,
+ PM8XXX_HSED_BIAS2,
+};
+
+#if defined(CONFIG_MFD_PM8XXX_MISC) || defined(CONFIG_MFD_PM8XXX_MISC_MODULE)
+
+/**
+ * pm8xxx_reset_pwr_off - switch all PM8XXX PMIC chips attached to the system to
+ * either reset or shutdown when they are turned off
+ * @reset: 0 = shudown the PMICs, 1 = shutdown and then restart the PMICs
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_reset_pwr_off(int reset);
+
+int pm8xxx_uart_gpio_mux_ctrl(enum pm8xxx_uart_path_sel uart_path_sel);
+
+/**
+ * pm8xxx_coincell_chg_config - Disables or enables the coincell charger, and
+ * configures its voltage and resistor settings.
+ * @chg_config: Holds both voltage and resistor values, and a
+ * switch to change the state of charger.
+ * If state is to disable the charger then
+ * both voltage and resistor are disregarded.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_coincell_chg_config(struct pm8xxx_coincell_chg *chg_config);
+
+/**
+ * pm8xxx_smpl_control - enables/disables SMPL detection
+ * @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
+ *
+ * This function enables or disables the Sudden Momentary Power Loss detection
+ * module. If SMPL detection is enabled, then when a sufficiently long power
+ * loss event occurs, the PMIC will automatically reset itself. If SMPL
+ * detection is disabled, then the PMIC will shutdown when power loss occurs.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_smpl_control(int enable);
+
+/**
+ * pm8xxx_smpl_set_delay - sets the SMPL detection time delay
+ * @delay: enum value corresponding to delay time
+ *
+ * This function sets the time delay of the SMPL detection module. If power
+ * is reapplied within this interval, then the PMIC reset automatically. The
+ * SMPL detection module must be enabled for this delay time to take effect.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_smpl_set_delay(enum pm8xxx_smpl_delay delay);
+
+/**
+ * pm8xxx_watchdog_reset_control - enables/disables watchdog reset detection
+ * @enable: 0 = shutdown when PS_HOLD goes low, 1 = reset when PS_HOLD goes low
+ *
+ * This function enables or disables the PMIC watchdog reset detection feature.
+ * If watchdog reset detection is enabled, then the PMIC will reset itself
+ * when PS_HOLD goes low. If it is not enabled, then the PMIC will shutdown
+ * when PS_HOLD goes low.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_watchdog_reset_control(int enable);
+
+/**
+ * pm8xxx_hard_reset_config - Allows different reset configurations
+ *
+ * config = DISABLE_HARD_RESET to disable hard reset
+ * = SHUTDOWN_ON_HARD_RESET to turn off the system on hard reset
+ * = RESTART_ON_HARD_RESET to restart the system on hard reset
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_hard_reset_config(enum pm8xxx_pon_config config);
+
+/**
+ * pm8xxx_stay_on - enables stay_on feature
+ *
+ * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
+ * signal so that some special functions like debugging could be
+ * performed.
+ *
+ * This feature should not be used in any product release.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_stay_on(void);
+
+/**
+ * pm8xxx_preload_dVdd - preload the dVdd regulator during off state.
+ *
+ * This can help to reduce fluctuations in the dVdd voltage during startup
+ * at the cost of additional off state current draw.
+ *
+ * This API should only be called if dVdd startup issues are suspected.
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_preload_dVdd(void);
+
+/**
+ * pm8xxx_usb_id_pullup - Control a pullup for USB ID
+ *
+ * @enable: enable (1) or disable (0) the pullup
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_usb_id_pullup(int enable);
+
+/**
+ * pm8xxx_aux_clk_control - Control an auxiliary clock
+ * @clk_id: ID of clock to be programmed, registers of XO_CNTRL2
+ * @divider: divisor to use when configuring desired clock
+ * @enable: enable (1) the designated clock with the supplied division,
+ * or disable (0) the designated clock
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_aux_clk_control(enum pm8xxx_aux_clk_id clk_id,
+ enum pm8xxx_aux_clk_div divider,
+ bool enable);
+
+/**
+ * pm8xxx_hsed_bias_control - Control the HSED_BIAS signal
+ * @bias: the bias line to be controlled (of the 3)
+ * @enable: enable/disable the bias line
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
+#else
+
+static inline int pm8xxx_reset_pwr_off(int reset)
+{
+ return -ENODEV;
+}
+static inline int
+pm8xxx_uart_gpio_mux_ctrl(enum pm8xxx_uart_path_sel uart_path_sel)
+{
+ return -ENODEV;
+}
+static inline int
+pm8xxx_coincell_chg_config(struct pm8xxx_coincell_chg *chg_config)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_smpl_set_delay(enum pm8xxx_smpl_delay delay)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_smpl_control(int enable)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_watchdog_reset_control(int enable)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_hard_reset_config(enum pm8xxx_pon_config config)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_stay_on(void)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_preload_dVdd(void)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_usb_id_pullup(int enable)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_aux_clk_control(enum pm8xxx_aux_clk_id clk_id,
+ enum pm8xxx_aux_clk_div divider, bool enable)
+{
+ return -ENODEV;
+}
+static inline int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias,
+ bool enable)
+{
+ return -ENODEV;
+}
+
+#endif
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/mpp.h b/include/linux/mfd/pm8xxx/mpp.h
new file mode 100644
index 0000000..2a934e5
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/mpp.h
@@ -0,0 +1,263 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __PM8XXX_MPP_H
+#define __PM8XXX_MPP_H
+
+#include <linux/errno.h>
+
+#define PM8XXX_MPP_DEV_NAME "pm8xxx-mpp"
+
+struct pm8xxx_mpp_core_data {
+ int base_addr;
+ int nmpps;
+};
+
+struct pm8xxx_mpp_platform_data {
+ struct pm8xxx_mpp_core_data core_data;
+ int mpp_base;
+};
+
+/**
+ * struct pm8xxx_mpp_config_data - structure to specify mpp configuration values
+ * @type: MPP type which determines the overall MPP function (i.e. digital
+ * in/out/bi, analog in/out, current sink, or test). It should be
+ * set to the value of one of PM8XXX_MPP_TYPE_D_*.
+ * @level: meaning depends upon MPP type specified
+ * @control: meaning depends upon MPP type specified
+ *
+ * Usage of level argument:
+ * 1. type = PM8XXX_MPP_TYPE_D_INPUT, PM8XXX_MPP_TYPE_D_OUTPUT,
+ * PM8XXX_MPP_TYPE_D_BI_DIR, or PM8XXX_MPP_TYPE_DTEST_OUTPUT -
+ *
+ * level specifies that digital logic level to use for the MPP. It should
+ * be set to the value of one of PM8XXX_MPP_DIG_LEVEL_*. Actual regulator
+ * connections for these level choices are PMIC chip specific.
+ *
+ * 2. type = PM8XXX_MPP_TYPE_A_INPUT -
+ *
+ * level specifies where in the PMIC chip the analog input value should
+ * be routed to. It should be set to the value of one of
+ * PM8XXX_MPP_AIN_AMUX_*.
+ *
+ * 3. type = PM8XXX_MPP_TYPE_A_OUTPUT -
+ *
+ * level specifies the output analog voltage reference level. It should
+ * be set to the value of one of PM8XXX_MPP_AOUT_LVL_*.
+ *
+ * 4. type = PM8XXX_MPP_TYPE_SINK or PM8XXX_MPP_TYPE_DTEST_SINK -
+ *
+ * level specifies the output current level. It should be set to the value
+ * of one of PM8XXX_MPP_CS_OUT_*.
+ *
+ * Usage of control argument:
+ * 1. type = PM8XXX_MPP_TYPE_D_INPUT -
+ *
+ * control specifies how the digital input should be routed in the chip.
+ * It should be set to the value of one of PM8XXX_MPP_DIN_TO_*.
+ *
+ * 2. type = PM8XXX_MPP_TYPE_D_OUTPUT -
+ *
+ * control specifies the digital output value. It should be set to the
+ * value of one of PM8XXX_MPP_DOUT_CTRL_*.
+ *
+ * 3. type = PM8XXX_MPP_TYPE_D_BI_DIR -
+ *
+ * control specifies the pullup resistor value. It should be set to the
+ * value of one of PM8XXX_MPP_BI_PULLUP_*.
+ *
+ * 4. type = PM8XXX_MPP_TYPE_A_INPUT -
+ *
+ * control is unused; a value of 0 is sufficient.
+ *
+ * 5. type = PM8XXX_MPP_TYPE_A_OUTPUT -
+ *
+ * control specifies if analog output is enabled. It should be set to the
+ * value of one of PM8XXX_MPP_AOUT_CTRL_*.
+ *
+ * 6. type = PM8XXX_MPP_TYPE_SINK -
+ *
+ * control specifies if current sinking is enabled. It should be set to
+ * the value of one of PM8XXX_MPP_CS_CTRL_*.
+ *
+ * 7. type = PM8XXX_MPP_TYPE_DTEST_SINK -
+ *
+ * control specifies if current sinking is enabled. It should be set to
+ * the value of one of PM8XXX_MPP_DTEST_CS_CTRL_*.
+ *
+ * 8. type = PM8XXX_MPP_TYPE_DTEST_OUTPUT -
+ *
+ * control specifies which DTEST bus value to output. It should be set to
+ * the value of one of PM8XXX_MPP_DTEST_*.
+ */
+struct pm8xxx_mpp_config_data {
+ unsigned type;
+ unsigned level;
+ unsigned control;
+};
+
+/* API */
+#if defined(CONFIG_GPIO_PM8XXX_MPP) || defined(CONFIG_GPIO_PM8XXX_MPP_MODULE)
+
+/**
+ * pm8xxx_mpp_config() - configure control options of a multi-purpose pin (MPP)
+ * @mpp: global GPIO number corresponding to the MPP
+ * @config: configuration to set for this MPP
+ * Context: can sleep
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_mpp_config(unsigned mpp, struct pm8xxx_mpp_config_data *config);
+
+#else
+
+static inline int pm8xxx_mpp_config(unsigned mpp,
+ struct pm8xxx_mpp_config_data *config)
+{
+ return -ENXIO;
+}
+
+#endif
+
+/* MPP Type: type */
+#define PM8XXX_MPP_TYPE_D_INPUT 0
+#define PM8XXX_MPP_TYPE_D_OUTPUT 1
+#define PM8XXX_MPP_TYPE_D_BI_DIR 2
+#define PM8XXX_MPP_TYPE_A_INPUT 3
+#define PM8XXX_MPP_TYPE_A_OUTPUT 4
+#define PM8XXX_MPP_TYPE_SINK 5
+#define PM8XXX_MPP_TYPE_DTEST_SINK 6
+#define PM8XXX_MPP_TYPE_DTEST_OUTPUT 7
+
+/* Digital Input/Output: level */
+#define PM8XXX_MPP_DIG_LEVEL_VIO_0 0
+#define PM8XXX_MPP_DIG_LEVEL_VIO_1 1
+#define PM8XXX_MPP_DIG_LEVEL_VIO_2 2
+#define PM8XXX_MPP_DIG_LEVEL_VIO_3 3
+#define PM8XXX_MPP_DIG_LEVEL_VIO_4 4
+#define PM8XXX_MPP_DIG_LEVEL_VIO_5 5
+#define PM8XXX_MPP_DIG_LEVEL_VIO_6 6
+#define PM8XXX_MPP_DIG_LEVEL_VIO_7 7
+
+/* Digital Input/Output: level [PM8058] */
+#define PM8058_MPP_DIG_LEVEL_VPH 0
+#define PM8058_MPP_DIG_LEVEL_S3 1
+#define PM8058_MPP_DIG_LEVEL_L2 2
+#define PM8058_MPP_DIG_LEVEL_L3 3
+
+/* Digital Input/Output: level [PM8901] */
+#define PM8901_MPP_DIG_LEVEL_MSMIO 0
+#define PM8901_MPP_DIG_LEVEL_DIG 1
+#define PM8901_MPP_DIG_LEVEL_L5 2
+#define PM8901_MPP_DIG_LEVEL_S4 3
+#define PM8901_MPP_DIG_LEVEL_VPH 4
+
+/* Digital Input/Output: level [PM8921] */
+#define PM8921_MPP_DIG_LEVEL_S4 1
+#define PM8921_MPP_DIG_LEVEL_L15 3
+#define PM8921_MPP_DIG_LEVEL_L17 4
+#define PM8921_MPP_DIG_LEVEL_VPH 7
+
+/* Digital Input/Output: level [PM8821] */
+#define PM8821_MPP_DIG_LEVEL_1P8 0
+#define PM8821_MPP_DIG_LEVEL_VPH 7
+
+/* Digital Input/Output: level [PM8018] */
+#define PM8018_MPP_DIG_LEVEL_L4 0
+#define PM8018_MPP_DIG_LEVEL_L14 1
+#define PM8018_MPP_DIG_LEVEL_S3 2
+#define PM8018_MPP_DIG_LEVEL_L6 3
+#define PM8018_MPP_DIG_LEVEL_L2 4
+#define PM8018_MPP_DIG_LEVEL_L5 5
+#define PM8018_MPP_DIG_LEVEL_VPH 7
+
+/* Digital Input/Output: level [PM8038] */
+#define PM8038_MPP_DIG_LEVEL_L20 0
+#define PM8038_MPP_DIG_LEVEL_L11 1
+#define PM8038_MPP_DIG_LEVEL_L5 2
+#define PM8038_MPP_DIG_LEVEL_L15 3
+#define PM8038_MPP_DIG_LEVEL_L17 4
+#define PM8038_MPP_DIG_LEVEL_VPH 7
+
+/* Digital Input: control */
+#define PM8XXX_MPP_DIN_TO_INT 0
+#define PM8XXX_MPP_DIN_TO_DBUS1 1
+#define PM8XXX_MPP_DIN_TO_DBUS2 2
+#define PM8XXX_MPP_DIN_TO_DBUS3 3
+
+/* Digital Output: control */
+#define PM8XXX_MPP_DOUT_CTRL_LOW 0
+#define PM8XXX_MPP_DOUT_CTRL_HIGH 1
+#define PM8XXX_MPP_DOUT_CTRL_MPP 2
+#define PM8XXX_MPP_DOUT_CTRL_INV_MPP 3
+
+/* Bidirectional: control */
+#define PM8XXX_MPP_BI_PULLUP_1KOHM 0
+#define PM8XXX_MPP_BI_PULLUP_OPEN 1
+#define PM8XXX_MPP_BI_PULLUP_10KOHM 2
+#define PM8XXX_MPP_BI_PULLUP_30KOHM 3
+
+/* Analog Input: level */
+#define PM8XXX_MPP_AIN_AMUX_CH5 0
+#define PM8XXX_MPP_AIN_AMUX_CH6 1
+#define PM8XXX_MPP_AIN_AMUX_CH7 2
+#define PM8XXX_MPP_AIN_AMUX_CH8 3
+#define PM8XXX_MPP_AIN_AMUX_CH9 4
+#define PM8XXX_MPP_AIN_AMUX_ABUS1 5
+#define PM8XXX_MPP_AIN_AMUX_ABUS2 6
+#define PM8XXX_MPP_AIN_AMUX_ABUS3 7
+
+/* Analog Output: level */
+#define PM8XXX_MPP_AOUT_LVL_1V25 0
+#define PM8XXX_MPP_AOUT_LVL_1V25_2 1
+#define PM8XXX_MPP_AOUT_LVL_0V625 2
+#define PM8XXX_MPP_AOUT_LVL_0V3125 3
+#define PM8XXX_MPP_AOUT_LVL_MPP 4
+#define PM8XXX_MPP_AOUT_LVL_ABUS1 5
+#define PM8XXX_MPP_AOUT_LVL_ABUS2 6
+#define PM8XXX_MPP_AOUT_LVL_ABUS3 7
+
+/* Analog Output: control */
+#define PM8XXX_MPP_AOUT_CTRL_DISABLE 0
+#define PM8XXX_MPP_AOUT_CTRL_ENABLE 1
+#define PM8XXX_MPP_AOUT_CTRL_MPP_HIGH_EN 2
+#define PM8XXX_MPP_AOUT_CTRL_MPP_LOW_EN 3
+
+/* Current Sink: level */
+#define PM8XXX_MPP_CS_OUT_5MA 0
+#define PM8XXX_MPP_CS_OUT_10MA 1
+#define PM8XXX_MPP_CS_OUT_15MA 2
+#define PM8XXX_MPP_CS_OUT_20MA 3
+#define PM8XXX_MPP_CS_OUT_25MA 4
+#define PM8XXX_MPP_CS_OUT_30MA 5
+#define PM8XXX_MPP_CS_OUT_35MA 6
+#define PM8XXX_MPP_CS_OUT_40MA 7
+
+/* Current Sink: control */
+#define PM8XXX_MPP_CS_CTRL_DISABLE 0
+#define PM8XXX_MPP_CS_CTRL_ENABLE 1
+#define PM8XXX_MPP_CS_CTRL_MPP_HIGH_EN 2
+#define PM8XXX_MPP_CS_CTRL_MPP_LOW_EN 3
+
+/* DTEST Current Sink: control */
+#define PM8XXX_MPP_DTEST_CS_CTRL_EN1 0
+#define PM8XXX_MPP_DTEST_CS_CTRL_EN2 1
+#define PM8XXX_MPP_DTEST_CS_CTRL_EN3 2
+#define PM8XXX_MPP_DTEST_CS_CTRL_EN4 3
+
+/* DTEST Digital Output: control */
+#define PM8XXX_MPP_DTEST_DBUS1 0
+#define PM8XXX_MPP_DTEST_DBUS2 1
+#define PM8XXX_MPP_DTEST_DBUS3 2
+#define PM8XXX_MPP_DTEST_DBUS4 3
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/nfc.h b/include/linux/mfd/pm8xxx/nfc.h
new file mode 100644
index 0000000..e58e0a9
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/nfc.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#ifndef __PM8XXX_NFC_H__
+#define __PM8XXX_NFC_H__
+
+struct pm8xxx_nfc_device;
+
+#define PM8XXX_NFC_DEV_NAME "pm8xxx-nfc"
+
+/* masks, flags and status */
+#define PM_NFC_VDDLDO_MON_LEVEL 0x0003
+#define PM_NFC_VPH_PWR_EN 0x0008
+#define PM_NFC_EXT_VDDLDO_EN 0x0010
+#define PM_NFC_EN 0x0020
+#define PM_NFC_LDO_EN 0x0040
+#define PM_NFC_SUPPORT_EN 0x0080
+
+#define PM_NFC_EXT_EN_HIGH 0x0100
+#define PM_NFC_MBG_EN_HIGH 0x0200
+#define PM_NFC_VDDLDO_OK_HIGH 0x0400
+#define PM_NFC_DTEST1_MODE 0x2000
+#define PM_NFC_ATEST_EN 0x4000
+#define PM_NFC_VDDLDO_MON_EN 0x8000
+
+#define PM_NFC_CTRL_REQ (PM_NFC_SUPPORT_EN |\
+ PM_NFC_LDO_EN |\
+ PM_NFC_EN |\
+ PM_NFC_EXT_VDDLDO_EN |\
+ PM_NFC_VPH_PWR_EN |\
+ PM_NFC_VDDLDO_MON_LEVEL)
+
+#define PM_NFC_TEST_REQ (PM_NFC_VDDLDO_MON_EN |\
+ PM_NFC_DTEST1_MODE |\
+ PM_NFC_ATEST_EN)
+
+#define PM_NFC_TEST_STATUS (PM_NFC_EXT_EN_HIGH |\
+ PM_NFC_MBG_EN_HIGH |\
+ PM_NFC_VDDLDO_OK_HIGH)
+
+/*
+ * pm8xxx_nfc_request - request a handle to access NFC device
+ */
+struct pm8xxx_nfc_device *pm8xxx_nfc_request(void);
+
+/*
+ * pm8xxx_nfc_config - configure NFC signals
+ *
+ * @nfcdev: the NFC device
+ * @mask: signal mask to configure
+ * @flags: control flags
+ */
+int pm8xxx_nfc_config(struct pm8xxx_nfc_device *nfcdev, u32 mask, u32 flags);
+
+/*
+ * pm8xxx_nfc_get_status - get NFC status
+ *
+ * @nfcdev: the NFC device
+ * @mask: of status mask to read
+ * @status: pointer to the status variable
+ */
+int pm8xxx_nfc_get_status(struct pm8xxx_nfc_device *nfcdev,
+ u32 mask, u32 *status);
+
+/*
+ * pm8xxx_nfc_free - free the NFC device
+ */
+void pm8xxx_nfc_free(struct pm8xxx_nfc_device *nfcdev);
+
+#endif /* __PM8XXX_NFC_H__ */
diff --git a/include/linux/mfd/pm8xxx/tm.h b/include/linux/mfd/pm8xxx/tm.h
new file mode 100644
index 0000000..6974754
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/tm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * Qualcomm PMIC PM8xxx Thermal Manager driver
+ */
+
+#ifndef __PM8XXX_TM_H
+#define __PM8XXX_TM_H
+
+#include <linux/errno.h>
+
+#define PM8XXX_TM_DEV_NAME "pm8xxx-tm"
+
+enum pm8xxx_tm_adc_type {
+ PM8XXX_TM_ADC_NONE, /* Estimates temp based on overload level. */
+ PM8XXX_TM_ADC_PM8058_ADC,
+ PM8XXX_TM_ADC_PM8XXX_ADC,
+};
+
+struct pm8xxx_tm_core_data {
+ int adc_channel;
+ unsigned long default_no_adc_temp;
+ enum pm8xxx_tm_adc_type adc_type;
+ u16 reg_addr_temp_alarm_ctrl;
+ u16 reg_addr_temp_alarm_pwm;
+ char *tm_name;
+ char *irq_name_temp_stat;
+ char *irq_name_over_temp;
+};
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/upl.h b/include/linux/mfd/pm8xxx/upl.h
new file mode 100644
index 0000000..b0e94a9
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/upl.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#ifndef __PM8XXX_UPL_H__
+#define __PM8XXX_UPL_H__
+
+struct pm8xxx_upl_device;
+
+#define PM8XXX_UPL_DEV_NAME "pm8xxx-upl"
+
+/* control masks and flags */
+#define PM8XXX_UPL_MOD_ENABLE_MASK (0x10)
+#define PM8XXX_UPL_MOD_ENABLE (0x10)
+#define PM8XXX_UPL_MOD_DISABLE (0x00)
+
+#define PM8XXX_UPL_OUT_DTEST_MASK (0xE0)
+#define PM8XXX_UPL_OUT_GPIO_ONLY (0x00)
+#define PM8XXX_UPL_OUT_DTEST_1 (0x80)
+#define PM8XXX_UPL_OUT_DTEST_2 (0xA0)
+#define PM8XXX_UPL_OUT_DTEST_3 (0xC0)
+#define PM8XXX_UPL_OUT_DTEST_4 (0xE0)
+
+#define PM8XXX_UPL_IN_A_MASK (0x01)
+#define PM8XXX_UPL_IN_A_GPIO (0x00)
+#define PM8XXX_UPL_IN_A_DTEST (0x01)
+#define PM8XXX_UPL_IN_B_MASK (0x02)
+#define PM8XXX_UPL_IN_B_GPIO (0x00)
+#define PM8XXX_UPL_IN_B_DTEST (0x02)
+#define PM8XXX_UPL_IN_C_MASK (0x04)
+#define PM8XXX_UPL_IN_C_GPIO (0x00)
+#define PM8XXX_UPL_IN_C_DTEST (0x04)
+#define PM8XXX_UPL_IN_D_MASK (0x08)
+#define PM8XXX_UPL_IN_D_GPIO (0x00)
+#define PM8XXX_UPL_IN_D_DTEST (0x08)
+
+/*
+ * pm8xxx_upl_request - request a handle to access UPL device
+ */
+struct pm8xxx_upl_device *pm8xxx_upl_request(void);
+
+int pm8xxx_upl_read_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 *truthtable);
+
+int pm8xxx_upl_write_truthtable(struct pm8xxx_upl_device *upldev,
+ u16 truthtable);
+
+/*
+ * pm8xxx_upl_config - configure UPL I/O settings and UPL enable/disable
+ *
+ * @upldev: the UPL device
+ * @mask: setting mask to configure
+ * @flags: setting flags
+ */
+int pm8xxx_upl_config(struct pm8xxx_upl_device *upldev, u32 mask, u32 flags);
+
+#endif /* __PM8XXX_UPL_H__ */
diff --git a/include/linux/mfd/pm8xxx/vibrator.h b/include/linux/mfd/pm8xxx/vibrator.h
new file mode 100644
index 0000000..cfea1c9
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/vibrator.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __PMIC8XXX_VIBRATOR_H__
+#define __PMIC8XXX_VIBRATOR_H__
+
+#define PM8XXX_VIBRATOR_DEV_NAME "pm8xxx-vib"
+
+enum pm8xxx_vib_en_mode {
+ PM8XXX_VIB_MANUAL,
+ PM8XXX_VIB_DTEST1,
+ PM8XXX_VIB_DTEST2,
+ PM8XXX_VIB_DTEST3
+};
+
+struct pm8xxx_vib_config {
+ u16 drive_mV;
+ u8 active_low;
+ enum pm8xxx_vib_en_mode enable_mode;
+};
+
+struct pm8xxx_vibrator_platform_data {
+ int initial_vibrate_ms;
+ int max_timeout_ms;
+ int level_mV;
+};
+
+int pm8xxx_vibrator_config(struct pm8xxx_vib_config *vib_config);
+
+#endif /* __PMIC8XXX_VIBRATOR_H__ */
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
new file mode 100644
index 0000000..7074c83
--- /dev/null
+++ b/include/linux/mfd/pmic8058.h
@@ -0,0 +1,137 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+/*
+ * Qualcomm PMIC8058 driver header file
+ *
+ */
+
+#ifndef __MFD_PMIC8058_H__
+#define __MFD_PMIC8058_H__
+
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/mfd/pm8xxx/mpp.h>
+#include <linux/mfd/pm8xxx/rtc.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+#include <linux/input/pmic8xxx-keypad.h>
+#include <linux/mfd/pm8xxx/vibrator.h>
+#include <linux/mfd/pm8xxx/nfc.h>
+#include <linux/mfd/pm8xxx/upl.h>
+#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
+#include <linux/leds-pmic8058.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/mfd/pm8xxx/tm.h>
+#include <linux/pmic8058-xoadc.h>
+#include <linux/regulator/pmic8058-regulator.h>
+#include <linux/regulator/pm8058-xo.h>
+#include <linux/pwm.h>
+#include <linux/pmic8058-pwm.h>
+
+#ifdef CONFIG_CHARGER_SMB328A
+#define PM8058_GPIO(n) ((n) - 1)
+#endif
+
+#define PM8058_GPIOS 40
+#define PM8058_MPPS 12
+
+#define PM8058_GPIO_BLOCK_START 24
+#define PM8058_MPP_BLOCK_START 16
+
+#define PM8058_NR_IRQS 256
+
+#define PM8058_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
+
+/* MPPs and GPIOs [0,N) */
+#define PM8058_MPP_IRQ(base, mpp) ((base) + \
+ PM8058_IRQ_BLOCK_BIT(16, (mpp)))
+#define PM8058_GPIO_IRQ(base, gpio) ((base) + \
+ PM8058_IRQ_BLOCK_BIT(24, (gpio)))
+
+/* PM8058 IRQ's */
+#define PM8058_VCP_IRQ PM8058_IRQ_BLOCK_BIT(1, 0)
+#define PM8058_CHGILIM_IRQ PM8058_IRQ_BLOCK_BIT(1, 3)
+#define PM8058_VBATDET_LOW_IRQ PM8058_IRQ_BLOCK_BIT(1, 4)
+#define PM8058_BATT_REPLACE_IRQ PM8058_IRQ_BLOCK_BIT(1, 5)
+#define PM8058_CHGINVAL_IRQ PM8058_IRQ_BLOCK_BIT(1, 6)
+#define PM8058_CHGVAL_IRQ PM8058_IRQ_BLOCK_BIT(1, 7)
+#define PM8058_CHG_END_IRQ PM8058_IRQ_BLOCK_BIT(2, 0)
+#define PM8058_FASTCHG_IRQ PM8058_IRQ_BLOCK_BIT(2, 1)
+#define PM8058_CHGSTATE_IRQ PM8058_IRQ_BLOCK_BIT(2, 3)
+#define PM8058_AUTO_CHGFAIL_IRQ PM8058_IRQ_BLOCK_BIT(2, 4)
+#define PM8058_AUTO_CHGDONE_IRQ PM8058_IRQ_BLOCK_BIT(2, 5)
+#define PM8058_ATCFAIL_IRQ PM8058_IRQ_BLOCK_BIT(2, 6)
+#define PM8058_ATC_DONE_IRQ PM8058_IRQ_BLOCK_BIT(2, 7)
+#define PM8058_OVP_OK_IRQ PM8058_IRQ_BLOCK_BIT(3, 0)
+#define PM8058_COARSE_DET_OVP_IRQ PM8058_IRQ_BLOCK_BIT(3, 1)
+#define PM8058_VCPMAJOR_IRQ PM8058_IRQ_BLOCK_BIT(3, 2)
+#define PM8058_CHG_GONE_IRQ PM8058_IRQ_BLOCK_BIT(3, 3)
+#define PM8058_CHGTLIMIT_IRQ PM8058_IRQ_BLOCK_BIT(3, 4)
+#define PM8058_CHGHOT_IRQ PM8058_IRQ_BLOCK_BIT(3, 5)
+#define PM8058_BATTTEMP_IRQ PM8058_IRQ_BLOCK_BIT(3, 6)
+#define PM8058_BATTCONNECT_IRQ PM8058_IRQ_BLOCK_BIT(3, 7)
+#define PM8058_BATFET_IRQ PM8058_IRQ_BLOCK_BIT(5, 4)
+#define PM8058_VBATDET_IRQ PM8058_IRQ_BLOCK_BIT(5, 5)
+#define PM8058_VBAT_IRQ PM8058_IRQ_BLOCK_BIT(5, 6)
+
+#define PM8058_RTC_IRQ PM8058_IRQ_BLOCK_BIT(6, 5)
+#define PM8058_RTC_ALARM_IRQ PM8058_IRQ_BLOCK_BIT(4, 7)
+#define PM8058_PWRKEY_REL_IRQ PM8058_IRQ_BLOCK_BIT(6, 2)
+#define PM8058_PWRKEY_PRESS_IRQ PM8058_IRQ_BLOCK_BIT(6, 3)
+#define PM8058_KEYPAD_IRQ PM8058_IRQ_BLOCK_BIT(9, 2)
+#define PM8058_KEYSTUCK_IRQ PM8058_IRQ_BLOCK_BIT(9, 3)
+#define PM8058_BATT_ALARM_IRQ PM8058_IRQ_BLOCK_BIT(5, 6)
+#define PM8058_SW_0_IRQ PM8058_IRQ_BLOCK_BIT(7, 1)
+#define PM8058_IR_0_IRQ PM8058_IRQ_BLOCK_BIT(7, 0)
+#define PM8058_SW_1_IRQ PM8058_IRQ_BLOCK_BIT(7, 3)
+#define PM8058_IR_1_IRQ PM8058_IRQ_BLOCK_BIT(7, 2)
+#define PM8058_SW_2_IRQ PM8058_IRQ_BLOCK_BIT(7, 5)
+#define PM8058_IR_2_IRQ PM8058_IRQ_BLOCK_BIT(7, 4)
+#define PM8058_TEMPSTAT_IRQ PM8058_IRQ_BLOCK_BIT(6, 7)
+#define PM8058_OVERTEMP_IRQ PM8058_IRQ_BLOCK_BIT(4, 2)
+#define PM8058_ADC_IRQ PM8058_IRQ_BLOCK_BIT(9, 4)
+#define PM8058_OSCHALT_IRQ PM8058_IRQ_BLOCK_BIT(4, 6)
+#define PM8058_CBLPWR_IRQ PM8058_IRQ_BLOCK_BIT(4, 3)
+#define PM8058_RESOUT_IRQ PM8058_IRQ_BLOCK_BIT(6, 4)
+
+struct pmic8058_charger_data {
+ unsigned int max_source_current;
+ int charger_type;
+ bool charger_data_valid;
+};
+
+struct pm8058_platform_data {
+ struct pm8xxx_mpp_platform_data *mpp_pdata;
+ struct pm8xxx_keypad_platform_data *keypad_pdata;
+ struct pm8xxx_gpio_platform_data *gpio_pdata;
+ struct pm8xxx_irq_platform_data *irq_pdata;
+ struct pm8xxx_rtc_platform_data *rtc_pdata;
+ struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
+ struct pm8xxx_vibrator_platform_data *vibrator_pdata;
+ struct pm8xxx_misc_platform_data *misc_pdata;
+ struct pmic8058_leds_platform_data *leds_pdata;
+ struct pmic8058_othc_config_pdata *othc0_pdata;
+ struct pmic8058_othc_config_pdata *othc1_pdata;
+ struct pmic8058_othc_config_pdata *othc2_pdata;
+ struct xoadc_platform_data *xoadc_pdata;
+ struct pm8058_pwm_pdata *pwm_pdata;
+ struct pm8058_vreg_pdata *regulator_pdatas;
+ int num_regulators;
+ struct pm8058_xo_pdata *xo_buffer_pdata;
+ int num_xo_buffers;
+ struct pmic8058_charger_data *charger_pdata;
+};
+
+#endif /* __MFD_PMIC8058_H__ */
diff --git a/include/linux/pmic8058-othc.h b/include/linux/pmic8058-othc.h
new file mode 100644
index 0000000..4c59845
--- /dev/null
+++ b/include/linux/pmic8058-othc.h
@@ -0,0 +1,146 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PMIC8058_OTHC_H__
+#define __PMIC8058_OTHC_H__
+
+/* Accessory detecion flags */
+#define OTHC_MICBIAS_DETECT BIT(0)
+#define OTHC_GPIO_DETECT BIT(1)
+#define OTHC_SWITCH_DETECT BIT(2)
+#define OTHC_ADC_DETECT BIT(3)
+
+enum othc_accessory_type {
+ OTHC_NO_DEVICE = 0,
+ OTHC_HEADSET = 1 << 0,
+ OTHC_HEADPHONE = 1 << 1,
+ OTHC_MICROPHONE = 1 << 2,
+ OTHC_ANC_HEADSET = 1 << 3,
+ OTHC_ANC_HEADPHONE = 1 << 4,
+ OTHC_ANC_MICROPHONE = 1 << 5,
+ OTHC_SVIDEO_OUT = 1 << 6,
+};
+
+struct accessory_adc_thres {
+ int min_threshold;
+ int max_threshold;
+};
+
+struct othc_accessory_info {
+ unsigned int accessory;
+ unsigned int detect_flags;
+ unsigned int gpio;
+ unsigned int active_low;
+ unsigned int key_code;
+ bool enabled;
+ struct accessory_adc_thres adc_thres;
+};
+
+enum othc_headset_type {
+ OTHC_HEADSET_NO,
+ OTHC_HEADSET_NC,
+};
+
+struct othc_regulator_config {
+ const char *regulator;
+ unsigned int max_uV;
+ unsigned int min_uV;
+};
+
+/* Signal control for OTHC module */
+enum othc_micbias_enable {
+ /* Turn off MICBIAS signal */
+ OTHC_SIGNAL_OFF,
+ /* Turn on MICBIAS signal when TCXO is enabled */
+ OTHC_SIGNAL_TCXO,
+ /* Turn on MICBIAS signal when PWM is high or TCXO is enabled */
+ OTHC_SIGNAL_PWM_TCXO,
+ /* MICBIAS always enabled */
+ OTHC_SIGNAL_ALWAYS_ON,
+};
+
+/* Number of MICBIAS lines supported by PMIC8058 */
+enum othc_micbias {
+ OTHC_MICBIAS_0,
+ OTHC_MICBIAS_1,
+ OTHC_MICBIAS_2,
+ OTHC_MICBIAS_MAX,
+};
+
+enum othc_micbias_capability {
+ /* MICBIAS used only for BIAS with on/off capability */
+ OTHC_MICBIAS,
+ /* MICBIAS used to support HSED functionality */
+ OTHC_MICBIAS_HSED,
+};
+
+struct othc_switch_info {
+ u32 min_adc_threshold;
+ u32 max_adc_threshold;
+ u32 key_code;
+};
+
+struct othc_n_switch_config {
+ u32 voltage_settling_time_ms;
+ u8 num_adc_samples;
+ uint32_t adc_channel;
+ struct othc_switch_info *switch_info;
+ u8 num_keys;
+ bool default_sw_en;
+ u8 default_sw_idx;
+};
+
+struct hsed_bias_config {
+ enum othc_headset_type othc_headset;
+ u16 othc_lowcurr_thresh_uA;
+ u16 othc_highcurr_thresh_uA;
+ u32 othc_hyst_prediv_us;
+ u32 othc_period_clkdiv_us;
+ u32 othc_hyst_clk_us;
+ u32 othc_period_clk_us;
+ int othc_wakeup;
+};
+
+/* Configuration data for HSED */
+struct othc_hsed_config {
+ struct hsed_bias_config *hsed_bias_config;
+ unsigned long detection_delay_ms;
+ /* Switch configuration */
+ unsigned long switch_debounce_ms;
+ bool othc_support_n_switch; /* Set if supporting > 1 switch */
+ struct othc_n_switch_config *switch_config;
+ /* Accessory configuration */
+ bool accessories_support;
+ bool accessories_adc_support;
+ uint32_t accessories_adc_channel;
+ struct othc_accessory_info *accessories;
+ int othc_num_accessories;
+ int video_out_gpio;
+ int ir_gpio;
+};
+
+struct pmic8058_othc_config_pdata {
+ enum othc_micbias micbias_select;
+ enum othc_micbias_enable micbias_enable;
+ enum othc_micbias_capability micbias_capability;
+ struct othc_hsed_config *hsed_config;
+ const char *hsed_name;
+ struct othc_regulator_config *micbias_regulator;
+};
+
+int pm8058_micbias_enable(enum othc_micbias micbias,
+ enum othc_micbias_enable enable);
+int pm8058_othc_svideo_enable(enum othc_micbias micbias,
+ bool enable);
+
+#endif /* __PMIC8058_OTHC_H__ */
diff --git a/include/linux/pmic8058-pwm.h b/include/linux/pmic8058-pwm.h
new file mode 100644
index 0000000..d380170
--- /dev/null
+++ b/include/linux/pmic8058-pwm.h
@@ -0,0 +1,148 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#ifndef __PMIC8058_PWM_H__
+#define __PMIC8058_PWM_H__
+
+/* The MAX value is computation limit. Hardware limit is 393 seconds. */
+#define PM_PWM_PERIOD_MAX (274 * USEC_PER_SEC)
+/* The MIN value is hardware limit. */
+#define PM_PWM_PERIOD_MIN 7 /* micro seconds */
+
+struct pm8058_pwm_pdata {
+ int (*config)(struct pwm_device *pwm, int ch, int on);
+ int (*enable)(struct pwm_device *pwm, int ch, int on);
+};
+
+#define PM_PWM_LUT_SIZE 64
+#define PM_PWM_LUT_DUTY_TIME_MAX 512 /* ms */
+#define PM_PWM_LUT_PAUSE_MAX (7000 * PM_PWM_LUT_DUTY_TIME_MAX)
+
+/* Flags for Look Up Table */
+#define PM_PWM_LUT_LOOP 0x01
+#define PM_PWM_LUT_RAMP_UP 0x02
+#define PM_PWM_LUT_REVERSE 0x04
+#define PM_PWM_LUT_PAUSE_HI_EN 0x10
+#define PM_PWM_LUT_PAUSE_LO_EN 0x20
+
+#define PM_PWM_LUT_NO_TABLE 0x100
+
+/* PWM LED ID */
+#define PM_PWM_LED_0 0
+#define PM_PWM_LED_1 1
+#define PM_PWM_LED_2 2
+#define PM_PWM_LED_KPD 3
+#define PM_PWM_LED_FLASH 4
+#define PM_PWM_LED_FLASH1 5
+
+/* PWM LED configuration mode */
+#define PM_PWM_CONF_NONE 0x0
+#define PM_PWM_CONF_PWM1 0x1
+#define PM_PWM_CONF_PWM2 0x2
+#define PM_PWM_CONF_PWM3 0x3
+#define PM_PWM_CONF_DTEST1 0x4
+#define PM_PWM_CONF_DTEST2 0x5
+#define PM_PWM_CONF_DTEST3 0x6
+#define PM_PWM_CONF_DTEST4 0x7
+
+/**
+ * PWM frequency/period control
+ *
+ * PWM Frequency = ClockFrequency / (N * T)
+ * or
+ * PWM Period = Clock Period * (N * T)
+ * where
+ * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
+ * T = Pre-divide * 2^m, m = 0..7 (exponent)
+ *
+ */
+
+enum pm_pwm_size {
+ PM_PWM_SIZE_6BIT = 6,
+ PM_PWM_SIZE_9BIT = 9,
+};
+
+enum pm_pwm_clk {
+ PM_PWM_CLK_1KHZ,
+ PM_PWM_CLK_32KHZ,
+ PM_PWM_CLK_19P2MHZ,
+};
+
+enum pm_pwm_pre_div {
+ PM_PWM_PDIV_2,
+ PM_PWM_PDIV_3,
+ PM_PWM_PDIV_5,
+ PM_PWM_PDIV_6,
+};
+
+/**
+ * struct pm8058_pwm_period - PWM period structure
+ * @pwm_size: enum pm_pwm_size
+ * @clk: enum pm_pwm_clk
+ * @pre_div: enum pm_pwm_pre_div
+ * @pre_div_exp: exponent of 2 as part of pre-divider: 0..7
+ */
+struct pm8058_pwm_period {
+ enum pm_pwm_size pwm_size;
+ enum pm_pwm_clk clk;
+ enum pm_pwm_pre_div pre_div;
+ int pre_div_exp;
+};
+
+/**
+ * pm8058_pwm_config_period - change PWM period
+ *
+ * @pwm: the PWM device
+ * @pwm_p: period in struct pm8058_pwm_period
+ */
+int pm8058_pwm_config_period(struct pwm_device *pwm,
+ struct pm8058_pwm_period *pwm_p);
+
+/**
+ * pm8058_pwm_config_duty_cycle - change PWM duty cycle
+ *
+ * @pwm: the PWM device
+ * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
+ */
+int pm8058_pwm_config_duty_cycle(struct pwm_device *pwm, int pwm_value);
+
+/**
+ * pm8058_pwm_lut_config - change a PWM device configuration to use LUT
+ *
+ * @pwm: the PWM device
+ * @period_us: period in micro second
+ * @duty_pct: arrary of duty cycles in percent, like 20, 50.
+ * @duty_time_ms: time for each duty cycle in millisecond
+ * @start_idx: start index in lookup table from 0 to MAX-1
+ * @idx_len: number of index
+ * @pause_lo: pause time in millisecond at low index
+ * @pause_hi: pause time in millisecond at high index
+ * @flags: control flags
+ */
+int pm8058_pwm_lut_config(struct pwm_device *pwm, int period_us,
+ int duty_pct[], int duty_time_ms, int start_idx,
+ int len, int pause_lo, int pause_hi, int flags);
+
+/**
+ * pm8058_pwm_lut_enable - control a PWM device to start/stop LUT ramp
+ *
+ * @pwm: the PWM device
+ * @start: to start (1), or stop (0)
+ */
+int pm8058_pwm_lut_enable(struct pwm_device *pwm, int start);
+
+int pm8058_pwm_set_dtest(struct pwm_device *pwm, int enable);
+
+int pm8058_pwm_config_led(struct pwm_device *pwm, int id,
+ int mode, int max_current);
+
+#endif /* __PMIC8058_PWM_H__ */
diff --git a/include/linux/pmic8058-xoadc.h b/include/linux/pmic8058-xoadc.h
new file mode 100644
index 0000000..5163b65
--- /dev/null
+++ b/include/linux/pmic8058-xoadc.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Qualcomm XOADC Driver header file
+ */
+
+#ifndef _PMIC8058_XOADC_H_
+#define _PMIC8058_XOADC_H_
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+struct xoadc_conv_state {
+ struct adc_conv_slot *context;
+ struct list_head slots;
+ struct mutex list_lock;
+};
+
+#define CHANNEL_VCOIN 0
+#define CHANNEL_VBAT 1
+#define CHANNEL_VCHG 2
+#define CHANNEL_CHG_MONITOR 3
+#define CHANNEL_VPH_PWR 4
+#define CHANNEL_MPP5 5
+#define CHANNEL_MPP6 6
+#define CHANNEL_MPP7 7
+#define CHANNEL_MPP8 8
+#define CHANNEL_MPP9 9
+#define CHANNEL_USB_VBUS 0Xa
+#define CHANNEL_DIE_TEMP 0Xb
+#define CHANNEL_INTERNAL 0xc
+#define CHANNEL_125V 0xd
+#define CHANNEL_INTERNAL_2 0Xe
+#define CHANNEL_MUXOFF 0xf
+
+#define XOADC_MPP_3 0x2
+#define XOADC_MPP_4 0X3
+#define XOADC_MPP_5 0x4
+#define XOADC_MPP_7 0x6
+#define XOADC_MPP_8 0x7
+#define XOADC_MPP_10 0X9
+
+#define XOADC_PMIC_0 0x0
+
+#define CHANNEL_ADC_625_MV 625
+
+struct xoadc_platform_data {
+ struct adc_properties *xoadc_prop;
+ u32 (*xoadc_setup) (void);
+ void (*xoadc_shutdown) (void);
+ void (*xoadc_mpp_config) (void);
+ int (*xoadc_vreg_set) (int);
+ int (*xoadc_vreg_setup) (void);
+ void (*xoadc_vreg_shutdown) (void);
+ u32 xoadc_num;
+ u32 xoadc_wakeup;
+};
+
+#ifdef CONFIG_PMIC8058_XOADC
+int32_t pm8058_xoadc_read_adc_code(uint32_t adc_instance, int32_t *data);
+
+int32_t pm8058_xoadc_select_chan_and_start_conv(uint32_t adc_instance,
+ struct adc_conv_slot *slot);
+
+void pm8058_xoadc_slot_request(uint32_t adc_instance,
+ struct adc_conv_slot **slot);
+
+void pm8058_xoadc_restore_slot(uint32_t adc_instance,
+ struct adc_conv_slot *slot);
+
+struct adc_properties *pm8058_xoadc_get_properties(uint32_t dev_instance);
+
+int32_t pm8058_xoadc_calibrate(uint32_t dev_instance,
+ struct adc_conv_slot *slot, int * calib_status);
+
+int32_t pm8058_xoadc_registered(void);
+
+int32_t pm8058_xoadc_calib_device(uint32_t adc_instance);
+
+#else
+
+static inline int32_t pm8058_xoadc_read_adc_code(uint32_t adc_instance,
+ int32_t *data)
+{ return -ENXIO; }
+
+static inline int32_t pm8058_xoadc_select_chan_and_start_conv(
+ uint32_t adc_instance, struct adc_conv_slot *slot)
+{ return -ENXIO; }
+
+static inline void pm8058_xoadc_slot_request(uint32_t adc_instance,
+ struct adc_conv_slot **slot)
+{ return; }
+
+static inline void pm8058_xoadc_restore_slot(uint32_t adc_instance,
+ struct adc_conv_slot *slot)
+{ return; }
+
+static inline struct adc_properties *pm8058_xoadc_get_properties(
+ uint32_t dev_instance)
+{ return NULL; }
+
+static inline int32_t pm8058_xoadc_calibrate(uint32_t dev_instance,
+ struct adc_conv_slot *slot, int *calib_status)
+{ return -ENXIO; }
+
+static inline int32_t pm8058_xoadc_registered(void)
+{ return -ENXIO; }
+
+static inline int32_t pm8058_xoadc_calib_device(uint32_t adc_instance)
+{ return -ENXIO; }
+#endif
+#endif
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 804b906..f10829c 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -92,7 +92,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_AUTHENTIC,
POWER_SUPPLY_PROP_TECHNOLOGY,
- POWER_SUPPLY_PROP_CYCLE_COUNT,
+ /* POWER_SUPPLY_PROP_CYCLE_COUNT, */
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
@@ -134,6 +134,17 @@ enum power_supply_property {
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
+ POWER_SUPPLY_PROP_BATT_TEMP,
+ POWER_SUPPLY_PROP_BATT_TEMP_ADC,
+ POWER_SUPPLY_PROP_BATT_VOL,
+ POWER_SUPPLY_PROP_BATT_VOL_ADC,
+ POWER_SUPPLY_PROP_BATT_VF_ADC,
+ POWER_SUPPLY_PROP_BATT_VOL_ADC_AVER,
+ POWER_SUPPLY_PROP_BATT_TEMP_ADC_AVER,
+ POWER_SUPPLY_PROP_BATT_VOL_AVER,
+ POWER_SUPPLY_PROP_BATT_TEMP_AVER,
+ POWER_SUPPLY_PROP_BATT_TYPE,
+ POWER_SUPPLY_PROP_BATT_FULL,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
diff --git a/include/linux/regulator/pm8058-xo.h b/include/linux/regulator/pm8058-xo.h
new file mode 100644
index 0000000..a2b8aeb
--- /dev/null
+++ b/include/linux/regulator/pm8058-xo.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __PM8058_XO_H__
+#define __PM8058_XO_H__
+
+#include <linux/regulator/machine.h>
+
+#define PM8058_XO_BUFFER_DEV_NAME "pm8058-xo-buffer"
+
+/* XO buffer control ids */
+#define PM8058_XO_ID_A0 0
+#define PM8058_XO_ID_A1 1
+
+#define PM8058_XO_ID_MAX (PM8058_XO_ID_A1 + 1)
+
+struct pm8058_xo_pdata {
+ struct regulator_init_data init_data;
+ int id;
+};
+
+#endif
diff --git a/include/linux/regulator/pmic8058-regulator.h b/include/linux/regulator/pmic8058-regulator.h
new file mode 100644
index 0000000..3eeaa61
--- /dev/null
+++ b/include/linux/regulator/pmic8058-regulator.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PMIC8058_REGULATOR_H__
+#define __PMIC8058_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+/* Low dropout regulator ids */
+#define PM8058_VREG_ID_L0 0
+#define PM8058_VREG_ID_L1 1
+#define PM8058_VREG_ID_L2 2
+#define PM8058_VREG_ID_L3 3
+#define PM8058_VREG_ID_L4 4
+#define PM8058_VREG_ID_L5 5
+#define PM8058_VREG_ID_L6 6
+#define PM8058_VREG_ID_L7 7
+#define PM8058_VREG_ID_L8 8
+#define PM8058_VREG_ID_L9 9
+#define PM8058_VREG_ID_L10 10
+#define PM8058_VREG_ID_L11 11
+#define PM8058_VREG_ID_L12 12
+#define PM8058_VREG_ID_L13 13
+#define PM8058_VREG_ID_L14 14
+#define PM8058_VREG_ID_L15 15
+#define PM8058_VREG_ID_L16 16
+#define PM8058_VREG_ID_L17 17
+#define PM8058_VREG_ID_L18 18
+#define PM8058_VREG_ID_L19 19
+#define PM8058_VREG_ID_L20 20
+#define PM8058_VREG_ID_L21 21
+#define PM8058_VREG_ID_L22 22
+#define PM8058_VREG_ID_L23 23
+#define PM8058_VREG_ID_L24 24
+#define PM8058_VREG_ID_L25 25
+
+/* Switched-mode power supply regulator ids */
+#define PM8058_VREG_ID_S0 26
+#define PM8058_VREG_ID_S1 27
+#define PM8058_VREG_ID_S2 28
+#define PM8058_VREG_ID_S3 29
+#define PM8058_VREG_ID_S4 30
+
+/* Low voltage switch regulator ids */
+#define PM8058_VREG_ID_LVS0 31
+#define PM8058_VREG_ID_LVS1 32
+
+/* Negative charge pump regulator id */
+#define PM8058_VREG_ID_NCP 33
+
+#define PM8058_VREG_MAX (PM8058_VREG_ID_NCP + 1)
+
+#define PM8058_VREG_PIN_CTRL_NONE 0x00
+#define PM8058_VREG_PIN_CTRL_A0 0x01
+#define PM8058_VREG_PIN_CTRL_A1 0x02
+#define PM8058_VREG_PIN_CTRL_D0 0x04
+#define PM8058_VREG_PIN_CTRL_D1 0x08
+
+/* Minimum high power mode loads in uA. */
+#define PM8058_VREG_LDO_50_HPM_MIN_LOAD 5000
+#define PM8058_VREG_LDO_150_HPM_MIN_LOAD 10000
+#define PM8058_VREG_LDO_300_HPM_MIN_LOAD 10000
+#define PM8058_VREG_SMPS_HPM_MIN_LOAD 50000
+
+/* Pin ctrl enables/disables or toggles high/low power modes */
+enum pm8058_vreg_pin_fn {
+ PM8058_VREG_PIN_FN_ENABLE = 0,
+ PM8058_VREG_PIN_FN_MODE,
+};
+
+struct pm8058_vreg_pdata {
+ struct regulator_init_data init_data;
+ int id;
+ unsigned pull_down_enable;
+ unsigned pin_ctrl;
+ enum pm8058_vreg_pin_fn pin_fn;
+};
+
+#endif
diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
new file mode 100644
index 0000000..5b2d0f3
--- /dev/null
+++ b/include/linux/wakelock.h
@@ -0,0 +1,90 @@
+/* include/linux/wakelock.h
+ *
+ * Copyright (C) 2007-2008 Google, 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.
+ *
+ */
+
+#ifndef _LINUX_WAKELOCK_H
+#define _LINUX_WAKELOCK_H
+
+#include <linux/list.h>
+#include <linux/ktime.h>
+
+/* A wake_lock prevents the system from entering suspend or other low power
+ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
+ * prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power
+ * states that cause large interrupt latencies or that disable a set of
+ * interrupts will not entered from idle until the wake_locks are released.
+ */
+
+enum {
+ WAKE_LOCK_SUSPEND, /* Prevent suspend */
+ WAKE_LOCK_TYPE_COUNT
+};
+
+struct wake_lock {
+#ifdef CONFIG_HAS_WAKELOCK
+ struct list_head link;
+ int flags;
+ const char *name;
+ unsigned long expires;
+#ifdef CONFIG_WAKELOCK_STAT
+ struct {
+ int count;
+ int expire_count;
+ int wakeup_count;
+ ktime_t total_time;
+ ktime_t prevent_suspend_time;
+ ktime_t max_time;
+ ktime_t last_time;
+ } stat;
+#endif
+#endif
+};
+
+#ifdef CONFIG_HAS_WAKELOCK
+
+void wake_lock_init(struct wake_lock *lock, int type, const char *name);
+void wake_lock_destroy(struct wake_lock *lock);
+void wake_lock(struct wake_lock *lock);
+void wake_lock_timeout(struct wake_lock *lock, long timeout);
+void wake_unlock(struct wake_lock *lock);
+
+/* wake_lock_active returns a non-zero value if the wake_lock is currently
+ * locked. If the wake_lock has a timeout, it does not check the timeout
+ * but if the timeout had aready been checked it will return 0.
+ */
+int wake_lock_active(struct wake_lock *lock);
+
+/* has_wake_lock returns 0 if no wake locks of the specified type are active,
+ * and non-zero if one or more wake locks are held. Specifically it returns
+ * -1 if one or more wake locks with no timeout are active or the
+ * number of jiffies until all active wake locks time out.
+ */
+long has_wake_lock(int type);
+
+#else
+
+static inline void wake_lock_init(struct wake_lock *lock, int type,
+ const char *name) {}
+static inline void wake_lock_destroy(struct wake_lock *lock) {}
+static inline void wake_lock(struct wake_lock *lock) {}
+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) {}
+static inline void wake_unlock(struct wake_lock *lock) {}
+
+static inline int wake_lock_active(struct wake_lock *lock) { return 0; }
+static inline long has_wake_lock(int type) { return 0; }
+
+#endif
+
+#endif
+
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists