summaryrefslogtreecommitdiff
path: root/arch/arm/mach-msm/pmic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm/pmic.c')
-rw-r--r--arch/arm/mach-msm/pmic.c1095
1 files changed, 1095 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c
new file mode 100644
index 000000000000..3c481a6bc180
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.c
@@ -0,0 +1,1095 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora Forum nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include <mach/pmic.h>
+
+#include "smd_rpcrouter.h"
+
+#define TRACE_PMIC 0
+
+#if TRACE_PMIC
+#define PMIC(x...) printk(KERN_INFO "[PMIC] " x)
+#else
+#define PMIC(x...) do {} while (0)
+#endif
+
+
+#define LIB_NULL_PROC 0
+#define LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define LP_MODE_CONTROL_PROC 2
+#define VREG_SET_LEVEL_PROC 3
+#define VREG_PULL_DOWN_SWITCH_PROC 4
+#define SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC 5
+#define SECURE_MPP_CONFIG_I_SINK_PROC 6
+#define RTC_START_PROC 7
+#define RTC_STOP_PROC 8
+#define RTC_GET_TIME_PROC 9
+#define RTC_ENABLE_ALARM_PROC 10
+#define RTC_DISABLE_ALARM_PROC 11
+#define RTC_GET_ALARM_TIME_PROC 12
+#define RTC_GET_ALARM_STATUS_PROC 13
+#define RTC_SET_TIME_ADJUST_PROC 14
+#define RTC_GET_TIME_ADJUST_PROC 15
+#define SET_LED_INTENSITY_PROC 16
+#define FLASH_LED_SET_CURRENT_PROC 17
+#define FLASH_LED_SET_MODE_PROC 18
+#define FLASH_LED_SET_POLARITY_PROC 19
+#define SPEAKER_CMD_PROC 20
+#define SET_SPEAKER_GAIN_PROC 21
+#define VIB_MOT_SET_VOLT_PROC 22
+#define VIB_MOT_SET_MODE_PROC 23
+#define VIB_MOT_SET_POLARITY_PROC 24
+#define VID_EN_PROC 25
+#define VID_IS_EN_PROC 26
+#define VID_LOAD_DETECT_EN_PROC 27
+#define MIC_EN_PROC 28
+#define MIC_IS_EN_PROC 29
+#define MIC_SET_VOLT_PROC 30
+#define MIC_GET_VOLT_PROC 31
+#define SPKR_EN_RIGHT_CHAN_PROC 32
+#define SPKR_IS_RIGHT_CHAN_EN_PROC 33
+#define SPKR_EN_LEFT_CHAN_PROC 34
+#define SPKR_IS_LEFT_CHAN_EN_PROC 35
+#define SET_SPKR_CONFIGURATION_PROC 36
+#define GET_SPKR_CONFIGURATION_PROC 37
+#define SPKR_GET_GAIN_PROC 38
+#define SPKR_IS_EN_PROC 39
+#define SPKR_EN_MUTE_PROC 40
+#define SPKR_IS_MUTE_EN_PROC 41
+#define SPKR_SET_DELAY_PROC 42
+#define SPKR_GET_DELAY_PROC 43
+#define SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC 44
+#define SET_SPEAKER_DELAY_PROC 45
+#define SPEAKER_1K6_ZIN_ENABLE_PROC 46
+#define SPKR_SET_MUX_HPF_CORNER_FREQ_PROC 47
+#define SPKR_GET_MUX_HPF_CORNER_FREQ_PROC 48
+#define SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC 49
+#define SPKR_EN_STEREO_PROC 50
+#define SPKR_IS_STEREO_EN_PROC 51
+#define SPKR_SELECT_USB_WITH_HPF_20HZ_PROC 52
+#define SPKR_IS_USB_WITH_HPF_20HZ_PROC 53
+#define SPKR_BYPASS_MUX_PROC 54
+#define SPKR_IS_MUX_BYPASSED_PROC 55
+#define SPKR_EN_HPF_PROC 56
+#define SPKR_IS_HPF_EN_PROC 57
+#define SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC 58
+#define SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC 59
+#define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60
+#define SPKR_SET_GAIN_PROC 61
+#define SPKR_EN_PROC 62
+#define HSED_SET_PERIOD_PROC 63
+#define HSED_SET_HYSTERESIS_PROC 64
+#define HSED_SET_CURRENT_THRESHOLD_PROC 65
+#define HSED_ENABLE_PROC 66
+
+
+/* rpc related */
+#define PMIC_RPC_TIMEOUT (5*HZ)
+
+#define PMIC_PDEV_NAME "rs00010001:00000000"
+#define PMIC_RPC_PROG 0x30000061
+#define PMIC_RPC_VER_1_1 0x00010001
+#define PMIC_RPC_VER_2_1 0x00020001
+
+/* error bit flags defined by modem side */
+#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE (0x0001)
+#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE (0x0002)
+#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE (0x0004)
+#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE (0x0008)
+#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE (0x0010)
+
+#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE (0x001F) /* all 5 previous */
+
+#define PM_ERR_FLAG__SBI_OPT_ERR (0x0080)
+#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED (0x0100)
+
+#define PMIC_BUFF_SIZE 256
+
+struct pmic_buf {
+ char *start; /* buffer start addr */
+ char *end; /* buffer end addr */
+ int size; /* buffer size */
+ char *data; /* payload begin addr */
+ int len; /* payload len */
+};
+
+static DEFINE_MUTEX(pmic_mtx);
+
+struct pmic_ctrl {
+ int inited;
+ struct pmic_buf tbuf;
+ struct pmic_buf rbuf;
+ struct msm_rpc_endpoint *endpoint;
+};
+
+static struct pmic_ctrl pmic_ctrl = {
+ .inited = -1,
+};
+
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf,
+ struct pmic_buf *rbuf, int proc);
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2,
+ uint data3, int num, int proc);
+static int pmic_rpc_set_struct(int, uint, uint *data, uint size, int proc);
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc);
+static int pmic_rpc_get_only(uint *getdata, int size, int proc);
+
+static int pmic_buf_init(void)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+
+ memset(&pmic_ctrl, 0, sizeof(pmic_ctrl));
+
+ pm->tbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+ if (pm->tbuf.start == NULL) {
+ printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pm->tbuf.data = pm->tbuf.start;
+ pm->tbuf.size = PMIC_BUFF_SIZE;
+ pm->tbuf.end = pm->tbuf.start + PMIC_BUFF_SIZE;
+ pm->tbuf.len = 0;
+
+ pm->rbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+ if (pm->rbuf.start == NULL) {
+ kfree(pm->tbuf.start);
+ printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ pm->rbuf.data = pm->rbuf.start;
+ pm->rbuf.size = PMIC_BUFF_SIZE;
+ pm->rbuf.end = pm->rbuf.start + PMIC_BUFF_SIZE;
+ pm->rbuf.len = 0;
+
+ pm->inited = 1;
+
+ return 0;
+}
+
+static inline void pmic_buf_reserve(struct pmic_buf *bp, int len)
+{
+ bp->data += len;
+}
+
+static inline void pmic_buf_reset(struct pmic_buf *bp)
+{
+ bp->data = bp->start;
+ bp->len = 0;
+}
+
+static int modem_to_linux_err(uint err)
+{
+ if (err == 0)
+ return 0;
+
+ if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE)
+ return -EINVAL; /* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */
+
+ if (err & PM_ERR_FLAG__SBI_OPT_ERR)
+ return -EIO;
+
+ if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED)
+ return -ENOSYS;
+
+ return -EPERM;
+}
+
+static int pmic_put_tx_data(struct pmic_buf *tp, uint datav)
+{
+ uint *lp;
+
+ if ((tp->size - tp->len) < sizeof(datav)) {
+ printk(KERN_ERR "%s: OVERFLOW size=%d len=%d\n",
+ __func__, tp->size, tp->len);
+ return -1;
+ }
+
+ lp = (uint *)tp->data;
+ *lp = cpu_to_be32(datav);
+ tp->data += sizeof(datav);
+ tp->len += sizeof(datav);
+
+ return sizeof(datav);
+}
+
+static int pmic_pull_rx_data(struct pmic_buf *rp, uint *datap)
+{
+ uint *lp;
+
+ if (rp->len < sizeof(*datap)) {
+ printk(KERN_ERR "%s: UNDERRUN len=%d\n", __func__, rp->len);
+ return -1;
+ }
+ lp = (uint *)rp->data;
+ *datap = be32_to_cpu(*lp);
+ rp->data += sizeof(*datap);
+ rp->len -= sizeof(*datap);
+
+ return sizeof(*datap);
+}
+
+
+/*
+ *
+ * +-------------------+
+ * | PROC cmd layer |
+ * +-------------------+
+ * | RPC layer |
+ * +-------------------+
+ *
+ * 1) network byte order
+ * 2) RPC request header(40 bytes) and RPC reply header (24 bytes)
+ * 3) each transaction consists of a request and reply
+ * 3) PROC (comamnd) layer has its own sub-protocol defined
+ * 4) sub-protocol can be grouped to follwoing 7 cases:
+ * a) set one argument, no get
+ * b) set two argument, no get
+ * c) set three argument, no get
+ * d) set a struct, no get
+ * e) set a argument followed by a struct, no get
+ * f) set a argument, get a argument
+ * g) no set, get either a argument or a struct
+ */
+
+/**
+ * pmic_rpc_req_reply() - send request and wait for reply
+ * @tbuf: buffer contains arguments
+ * @rbuf: buffer to be filled with arguments at reply
+ * @proc: command/request id
+ *
+ * This function send request to modem and wait until reply received
+ */
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf,
+ int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ int ans, len;
+
+
+ if ((pm->endpoint == NULL) || IS_ERR(pm->endpoint)) {
+ pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG,
+ PMIC_RPC_VER_2_1, 0);
+ if (IS_ERR(pm->endpoint)) {
+ pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG,
+ PMIC_RPC_VER_1_1, 0);
+ }
+
+ if (IS_ERR(pm->endpoint)) {
+ ans = PTR_ERR(pm->endpoint);
+ printk(KERN_ERR "%s: init rpc failed! ans = %d\n",
+ __func__, ans);
+ return ans;
+ }
+ }
+
+ /*
+ * data is point to next available space at this moment,
+ * move it back to beginning of request header and increase
+ * the length
+ */
+ tbuf->data = tbuf->start;
+ tbuf->len += sizeof(struct rpc_request_hdr);
+
+ len = msm_rpc_call_reply(pm->endpoint, proc,
+ tbuf->data, tbuf->len,
+ rbuf->data, rbuf->size,
+ PMIC_RPC_TIMEOUT);
+
+ if (len <= 0) {
+ printk(KERN_ERR "%s: rpc failed! len = %d\n", __func__, len);
+ pm->endpoint = NULL; /* re-connect later ? */
+ return len;
+ }
+
+ rbuf->len = len;
+ /* strip off rpc_reply_hdr */
+ rbuf->data += sizeof(struct rpc_reply_hdr);
+ rbuf->len -= sizeof(struct rpc_reply_hdr);
+
+ return rbuf->len;
+}
+
+/**
+ * pmic_rpc_set_only() - set arguments and no get
+ * @data0: first argumrnt
+ * @data1: second argument
+ * @data2: third argument
+ * @data3: fourth argument
+ * @num: number of argument
+ * @proc: command/request id
+ *
+ * This function covers case a, b, and c
+ */
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2, uint data3,
+ int num, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ int stat;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ if (num > 0)
+ pmic_put_tx_data(tp, data0);
+
+ if (num > 1)
+ pmic_put_tx_data(tp, data1);
+
+ if (num > 2)
+ pmic_put_tx_data(tp, data2);
+
+ if (num > 3)
+ pmic_put_tx_data(tp, data3);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_struct() - set the whole struct
+ * @xflag: indicates an extra argument
+ * @xdata: the extra argument
+ * @*data: starting address of struct
+ * @size: size of struct
+ * @proc: command/request id
+ *
+ * This fucntion covers case d and e
+ */
+static int pmic_rpc_set_struct(int xflag, uint xdata, uint *data, uint size,
+ int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ if (xflag)
+ pmic_put_tx_data(tp, xdata);
+
+ more_data = 1; /* tell server there have more data followed */
+ pmic_put_tx_data(tp, more_data);
+
+ size >>= 2;
+ for (i = 0; i < size; i++) {
+ pmic_put_tx_data(tp, *data);
+ data++;
+ }
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_get() - set one argument and get one argument
+ * @setdata: set argument
+ * @*getdata: memory to store argumnet
+ * @size: size of memory
+ * @proc: command/request id
+ *
+ * This function covers case f
+ */
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ unsigned int *lp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ pmic_put_tx_data(tp, setdata);
+
+ /*
+ * more_data = TRUE to ask server reply with requested datum
+ * otherwise, server will reply without datum
+ */
+ more_data = (getdata != NULL);
+ pmic_put_tx_data(tp, more_data);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+ pmic_pull_rx_data(rp, &more_data);
+
+ if (more_data) { /* more data followed */
+ size >>= 2;
+ lp = getdata;
+ for (i = 0; i < size; i++) {
+ if (pmic_pull_rx_data(rp, lp++) < 0)
+ break; /* not supposed to happen */
+ }
+ }
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_get_only() - get one or more than one arguments
+ * @*getdata: memory to store arguments
+ * @size: size of mmory
+ * @proc: command/request id
+ *
+ * This function covers case g
+ */
+static int pmic_rpc_get_only(uint *getdata, int size, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ unsigned int *lp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ /*
+ * more_data = TRUE to ask server reply with requested datum
+ * otherwise, server will reply without datum
+ */
+ more_data = (getdata != NULL);
+ pmic_put_tx_data(tp, more_data);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+ pmic_pull_rx_data(rp, &more_data);
+
+ if (more_data) { /* more data followed */
+ size >>= 2;
+ lp = getdata;
+ for (i = 0; i < size; i++) {
+ if (pmic_pull_rx_data(rp, lp++) < 0)
+ break; /* not supposed to happen */
+ }
+ }
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id)
+{
+ return pmic_rpc_set_only(cmd, id, 0, 0, 2, LP_MODE_CONTROL_PROC);
+}
+EXPORT_SYMBOL(pmic_lp_mode_control);
+
+int pmic_vreg_set_level(enum vreg_id vreg, int level)
+{
+ return pmic_rpc_set_only(vreg, level, 0, 0, 2, VREG_SET_LEVEL_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_set_level);
+
+int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id)
+{
+ return pmic_rpc_set_only(cmd, id, 0, 0, 2, VREG_PULL_DOWN_SWITCH_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_pull_down_switch);
+
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+ enum mpp_dlogic_level level,
+ enum mpp_dlogic_out_ctrl out)
+{
+ return pmic_rpc_set_only(which, level, out, 0, 3,
+ SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_control_digital_output);
+
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+ enum mpp_i_sink_level level,
+ enum mpp_i_sink_switch onoff)
+{
+ return pmic_rpc_set_only(which, level, onoff, 0, 3,
+ SECURE_MPP_CONFIG_I_SINK_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_i_sink);
+
+int pmic_secure_mpp_config_digital_input(enum mpp_which which,
+ enum mpp_dlogic_level level,
+ enum mpp_dlogic_in_dbus dbus)
+{
+ return pmic_rpc_set_only(which, level, dbus, 0, 3,
+ SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_digital_input);
+
+int pmic_rtc_start(struct rtc_time *time)
+{
+ return pmic_rpc_set_struct(0, 0, (uint *)time, sizeof(*time),
+ RTC_START_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_start);
+
+int pmic_rtc_stop(void)
+{
+ return pmic_rpc_set_only(0, 0, 0, 0, 0, RTC_STOP_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_stop);
+
+int pmic_rtc_get_time(struct rtc_time *time)
+{
+ return pmic_rpc_get_only((uint *)time, sizeof(*time),
+ RTC_GET_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time);
+
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+ struct rtc_time *time)
+{
+ return pmic_rpc_set_struct(1, alarm, (uint *)time, sizeof(*time),
+ RTC_ENABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_enable_alarm);
+
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm)
+{
+ return pmic_rpc_set_only(alarm, 0, 0, 0, 1, RTC_DISABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_disable_alarm);
+
+int pmic_rtc_get_alarm_time(enum rtc_alarm alarm,
+ struct rtc_time *time)
+{
+ return pmic_rpc_set_get(alarm, (uint *)time, sizeof(*time),
+ RTC_GET_ALARM_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_time);
+
+int pmic_rtc_get_alarm_status(uint *status)
+{
+ return pmic_rpc_get_only(status, sizeof(*status),
+ RTC_GET_ALARM_STATUS_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_status);
+
+int pmic_rtc_set_time_adjust(uint adjust)
+{
+ return pmic_rpc_set_only(adjust, 0, 0, 0, 1,
+ RTC_SET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_set_time_adjust);
+
+int pmic_rtc_get_time_adjust(uint *adjust)
+{
+ return pmic_rpc_get_only(adjust, sizeof(*adjust),
+ RTC_GET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time_adjust);
+
+/*
+ * generic speaker
+ */
+int pmic_speaker_cmd(const enum spkr_cmd cmd)
+{
+ return pmic_rpc_set_only(cmd, 0, 0, 0, 1, SPEAKER_CMD_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_cmd);
+
+int pmic_set_spkr_configuration(struct spkr_config_mode *cfg)
+{
+ return pmic_rpc_set_struct(0, 0, (uint *)cfg, sizeof(*cfg),
+ SET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_set_spkr_configuration);
+
+int pmic_get_spkr_configuration(struct spkr_config_mode *cfg)
+{
+ return pmic_rpc_get_only((uint *)cfg, sizeof(*cfg),
+ GET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_get_spkr_configuration);
+
+int pmic_spkr_en_right_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_RIGHT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_right_chan);
+
+int pmic_spkr_is_right_chan_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_RIGHT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_chan_en);
+
+int pmic_spkr_en_left_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_left_chan);
+
+int pmic_spkr_is_left_chan_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_LEFT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_left_chan_en);
+
+int pmic_set_speaker_gain(enum spkr_gain gain)
+{
+ return pmic_rpc_set_only(gain, 0, 0, 0, 1, SET_SPEAKER_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_gain);
+
+int pmic_set_speaker_delay(enum spkr_dly delay)
+{
+ return pmic_rpc_set_only(delay, 0, 0, 0, 1, SET_SPEAKER_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_delay);
+
+int pmic_speaker_1k6_zin_enable(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPEAKER_1K6_ZIN_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_1k6_zin_enable);
+
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq freq)
+{
+ return pmic_rpc_set_only(freq, 0, 0, 0, 1,
+ SPKR_SET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_mux_hpf_corner_freq);
+
+int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq *freq)
+{
+ return pmic_rpc_get_only(freq, sizeof(*freq),
+ SPKR_GET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_mux_hpf_corner_freq);
+
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_SELECT_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_select_usb_with_hpf_20hz);
+
+int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_usb_with_hpf_20hz);
+
+int pmic_spkr_bypass_mux(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_BYPASS_MUX_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_bypass_mux);
+
+int pmic_spkr_is_mux_bypassed(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_MUX_BYPASSED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mux_bypassed);
+
+int pmic_spkr_en_hpf(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_HPF_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_hpf);
+
+int pmic_spkr_is_hpf_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_HPF_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_hpf_en);
+
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_sink_curr_from_ref_volt_cir);
+
+int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_sink_curr_from_ref_volt_cir_en);
+
+/*
+ * speaker indexed by left_right
+ */
+int pmic_spkr_en(enum spkr_left_right left_right, uint enable)
+{
+ return pmic_rpc_set_only(left_right, enable, 0, 0, 2, SPKR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en);
+
+int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled)
+{
+ return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+ SPKR_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_en);
+
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain)
+{
+ return pmic_rpc_set_only(left_right, gain, 0, 0, 2, SPKR_SET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_gain);
+
+int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain)
+{
+ return pmic_rpc_set_get(left_right, gain, sizeof(*gain),
+ SPKR_GET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_gain);
+
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay)
+{
+ return pmic_rpc_set_only(left_right, delay, 0, 0, 2,
+ SPKR_SET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_delay);
+
+int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay)
+{
+ return pmic_rpc_set_get(left_right, delay, sizeof(*delay),
+ SPKR_GET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_delay);
+
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled)
+{
+ return pmic_rpc_set_only(left_right, enabled, 0, 0, 2,
+ SPKR_EN_MUTE_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_mute);
+
+int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled)
+{
+ return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+ SPKR_IS_MUTE_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mute_en);
+
+/*
+ * mic
+ */
+int pmic_mic_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, MIC_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_en);
+
+int pmic_mic_is_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled), MIC_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_is_en);
+
+int pmic_mic_set_volt(enum mic_volt vol)
+{
+ return pmic_rpc_set_only(vol, 0, 0, 0, 1, MIC_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_set_volt);
+
+int pmic_mic_get_volt(enum mic_volt *voltage)
+{
+ return pmic_rpc_get_only(voltage, sizeof(*voltage), MIC_GET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_get_volt);
+
+int pmic_vib_mot_set_volt(uint vol)
+{
+ return pmic_rpc_set_only(vol, 0, 0, 0, 1, VIB_MOT_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_volt);
+
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode)
+{
+ return pmic_rpc_set_only(mode, 0, 0, 0, 1, VIB_MOT_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_mode);
+
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol)
+{
+ return pmic_rpc_set_only(pol, 0, 0, 0, 1, VIB_MOT_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_polarity);
+
+int pmic_vid_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_en);
+
+int pmic_vid_is_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled), VID_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_is_en);
+
+int pmic_vid_load_detect_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_LOAD_DETECT_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_load_detect_en);
+
+int pmic_set_led_intensity(enum ledtype type, int level)
+{
+ return pmic_rpc_set_only(type, level, 0, 0, 2, SET_LED_INTENSITY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_led_intensity);
+
+int pmic_flash_led_set_current(const uint16_t milliamps)
+{
+ return pmic_rpc_set_only(milliamps, 0, 0, 0, 1,
+ FLASH_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_current);
+
+int pmic_flash_led_set_mode(enum flash_led_mode mode)
+{
+ return pmic_rpc_set_only((int)mode, 0, 0, 0, 1,
+ FLASH_LED_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_mode);
+
+int pmic_flash_led_set_polarity(enum flash_led_pol pol)
+{
+ return pmic_rpc_set_only((int)pol, 0, 0, 0, 1,
+ FLASH_LED_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_polarity);
+
+int pmic_spkr_add_right_left_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_ADD_RIGHT_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_add_right_left_chan);
+
+int pmic_spkr_is_right_left_chan_added(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_left_chan_added);
+
+int pmic_spkr_en_stereo(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_STEREO_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_stereo);
+
+int pmic_spkr_is_stereo_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_STEREO_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_stereo_en);
+
+int pmic_hsed_set_period(
+ enum hsed_controller controller,
+ enum hsed_period_pre_div period_pre_div,
+ enum hsed_period_time period_time
+)
+{
+ return pmic_rpc_set_only(controller, period_pre_div, period_time, 0,
+ 3,
+ HSED_SET_PERIOD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_period);
+
+int pmic_hsed_set_hysteresis(
+ enum hsed_controller controller,
+ enum hsed_hyst_pre_div hyst_pre_div,
+ enum hsed_hyst_time hyst_time
+)
+{
+ return pmic_rpc_set_only(controller, hyst_pre_div, hyst_time, 0,
+ 3,
+ HSED_SET_HYSTERESIS_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_hysteresis);
+
+int pmic_hsed_set_current_threshold(
+ enum hsed_controller controller,
+ enum hsed_switch switch_hsed,
+ uint32_t current_threshold
+)
+{
+ return pmic_rpc_set_only(controller, switch_hsed, current_threshold, 0,
+ 3,
+ HSED_SET_CURRENT_THRESHOLD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_current_threshold);
+
+int pmic_hsed_enable(
+ enum hsed_controller controller,
+ enum hsed_enable enable_hsed
+)
+{
+ return pmic_rpc_set_only(controller, enable_hsed, 0, 0,
+ 2,
+ HSED_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_enable);