From 0dc1f819dcf7ed4952d5a80a4e9cc417c217717a Mon Sep 17 00:00:00 2001 From: Markinus Date: Fri, 27 Aug 2010 19:16:44 +0200 Subject: [PATCH] pm: add global pm switching function This function is for switchiung between different ways in AMSS Version to set settings. Like pcom and dex --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/pmic_global.c | 228 ++++++++++++++++++++++++++++++++ arch/arm/mach-msm/pmic_global.h | 62 +++++++++ 3 files changed, 291 insertions(+) create mode 100644 arch/arm/mach-msm/pmic_global.c create mode 100644 arch/arm/mach-msm/pmic_global.h diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 04e13643..986f5b18 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -4,6 +4,7 @@ obj-y += devices.o pwrtest.o obj-y += proc_comm.o obj-y += dex_comm.o obj-y += amss_para.o +obj-y += pmic_global.o obj-y += vreg.o obj-y += pmic.o obj-y += remote_spinlock.o diff --git a/arch/arm/mach-msm/pmic_global.c b/arch/arm/mach-msm/pmic_global.c new file mode 100644 index 00000000..89060afe --- /dev/null +++ b/arch/arm/mach-msm/pmic_global.c @@ -0,0 +1,228 @@ +/* arch/arm/mach-msm/pmic_global.c + * + * Author: Markinus + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "pmic_global.h" + +#include +#include + +/* rpc related */ +#define PM_RPC_TIMEOUT (5*HZ) + +#define PM_RPC_PROG 0x30000060 +#define PM_RPC_VER 0x00010001 + +#define PM_RPC_PROC_SET_VREG (0x3) + + +/* 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) + +#define PM_ERR_FLAG__SBI_OPT_ERR (0x0080) +#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED (0x0100) + +#define PM_BUFF_SIZE 256 + +static DEFINE_MUTEX(global_pm_mutex); +static struct msm_rpc_endpoint *pm_ept; + + +static int modem_to_linux_err(uint err) +{ + if (err == 0) + return 0; + pr_err("RPC ERROR: %x\n", err); + if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE) + return -EINVAL; + + if (err & PM_ERR_FLAG__SBI_OPT_ERR) + return -EIO; + + if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED) + return -ENOSYS; + + return -EPERM; +} + + +/* + * 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 1 case: + * set three argument + */ + +/* Returns number of reply bytes (minus reply header size) or + * negative value on error. + */ +static int pm_rpc(int proc, void *msg, int msglen, void *rep, int replen) +{ + int r; + mutex_lock(&global_pm_mutex); + + if (!pm_ept) { + pm_ept = msm_rpc_connect(PM_RPC_PROG, PM_RPC_VER, 0); + if (!pm_ept) { + pr_err("pmic: cannot connect to rpc server\n"); + r = -ENODEV; + goto done; + } + } + r = msm_rpc_call_reply(pm_ept, proc, msg, msglen, + rep, replen, PM_RPC_TIMEOUT); + if (r >= 0) { + if (r < sizeof(struct rpc_reply_hdr)) { + r = -EIO; + goto done; + } + r -= sizeof(struct rpc_reply_hdr); + } +done: + mutex_unlock(&global_pm_mutex); + return r; +} + +struct pm_reply { + struct rpc_reply_hdr hdr; + uint32_t status; + uint32_t data; +}; + +/** + * pm_rpc_set_only() - set arguments and no get + * @data0: first argumrnt + * @data1: second argument + * @data2: third argument + * @num: number of argument + * @proc: command/request id + * + */ +static int pm_rpc_set_only(uint data0, uint data1, uint data2, uint num, uint proc) +{ + struct { + struct rpc_request_hdr hdr; + uint32_t data[3]; + } msg; + + struct pm_reply rep; + int r; + + if (num > 3) + return -EINVAL; + + msg.data[0] = cpu_to_be32(data0); + msg.data[1] = cpu_to_be32(data1); + msg.data[2] = cpu_to_be32(data2); + + r = pm_rpc(proc, &msg, + sizeof(struct rpc_request_hdr) + num * sizeof(uint32_t), + &rep, sizeof(rep)); + if (r < 0) + return 0; + if (r < sizeof(uint32_t)) + return -EIO; + + return modem_to_linux_err(be32_to_cpu(rep.status)); +} + + +int pmic_glb_set_vreg(int enable, enum vreg_id id) +{ + switch(__amss_version) { + case 5225: + case 6125: + case 6150: + id = 1U << id; + if(enable) { + return dex_comm(DEX_PMIC_REG_ON, &id, 0); + } + else { + return dex_comm(DEX_PMIC_REG_OFF, &id, 0); + } + break; + case 1550: + return pm_rpc_set_only(enable, id, 1, 3, PM_RPC_PROC_SET_VREG); + break; + default: + return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + break; + } +} + +int pmic_glb_vreg_set_level(enum vreg_id id, unsigned millivolt) +{ + switch(__amss_version) { + case 5225: + case 6125: + case 6150: + id = 1U << id; + return dex_comm(DEX_PMIC_REG_VOLTAGE, &id, &millivolt); + break; + case 1550: + return pmic_vreg_set_level(id, millivolt); + break; + default: + return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &millivolt); + break; + } +} + +int pmic_glb_power_down() +{ + switch(__amss_version) { + case 1550: + case 5225: + case 6125: + case 6150: + return dex_comm(DEX_POWER_OFF, 0, 0); + break; + default: + return msm_proc_comm(PCOM_POWER_DOWN, 0, 0); + break; + } +} + +int pmic_glb_reset_chip(unsigned restart_reason) +{ + switch(__amss_version) { + case 1550: + case 5225: + case 6125: + case 6150: + printk(KERN_ERR "No msm_hw_reset_hook() available! System halted.\n"); + return 0; + break; + default: + return msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); + break; + } +} + + diff --git a/arch/arm/mach-msm/pmic_global.h b/arch/arm/mach-msm/pmic_global.h new file mode 100644 index 00000000..4c3f4d5c --- /dev/null +++ b/arch/arm/mach-msm/pmic_global.h @@ -0,0 +1,62 @@ +/* arch/arm/mach-msm/pmic_global.h + * + * Author: Markinus + * The entry header file for all pm functions. If we have differences between devices then + * we have to replace a define with a function and put it in the c file. + * + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "pmic.h" +#include "dex_comm.h" + +// direct defines to functions, if same for all amss +#define pmic_glb_lp_mode_control(a,b) pmic_lp_mode_control(a, b) +#define pmic_glb_secure_mpp_control_digital_output(a, b, c) pmic_secure_mpp_control_digital_output(a, b, c) +#define pmic_glb_secure_mpp_config_i_sink(a, b, c) pmic_secure_mpp_config_i_sink(a, b, c) +#define pmic_glb_secure_mpp_config_digital_input(a, b, c) pmic_secure_mpp_config_digital_input(a, b, c) + +#define pmic_glb_speaker_cmd(a) pmic_speaker_cmd(a) +#define pmic_glb_set_spkr_configuration(a) pmic_set_spkr_configuration(a) +#define pmic_glb_spkr_en_right_chan(a) pmic_spkr_en_right_chan(a) +#define pmic_glb_spkr_en_left_chan(a) pmic_spkr_en_left_chan(a) +#define pmic_glb_spkr_en(a, b) pmic_spkr_en(a, b) +#define pmic_glb_spkr_set_gain(a, b) pmic_spkr_set_gain(a, b) +#define pmic_glb_set_speaker_gain(a) pmic_set_speaker_gain(a) +#define pmic_glb_set_speaker_delay(a) pmic_set_speaker_delay(a) +#define pmic_glb_speaker_1k6_zin_enable(a) pmic_speaker_1k6_zin_enable(a) +#define pmic_glb_spkr_set_mux_hpf_corner_freq(a) pmic_spkr_set_mux_hpf_corner_freq(a) +#define pmic_glb_spkr_select_usb_with_hpf_20hz(a) pmic_spkr_select_usb_with_hpf_20hz(a) +#define pmic_glb_spkr_bypass_mux(a) pmic_spkr_bypass_mux(a) +#define pmic_glb_spkr_en_hpf(a) pmic_spkr_en_hpf(a) +#define pmic_glb_spkr_en_sink_curr_from_ref_volt_cir(a) pmic_spkr_en_sink_curr_from_ref_volt_cir(a) +#define pmic_glb_spkr_set_delay(a, b) pmic_spkr_set_delay(a, b) +#define pmic_glb_spkr_en_mute(a, b) pmic_spkr_en_mut(a, b) +#define pmic_glb_mic_en(a) pmic_mic_en(a) +#define pmic_glb_mic_set_volt(a) pmic_mic_set_volt(a) +#define pmic_glb_set_led_intensity(a, b) pmic_set_led_intensity(a, b) +#define pmic_glb_flash_led_set_current(a) pmic_flash_led_set_current(a) +#define pmic_glb_flash_led_set_mode(a) pmic_flash_led_set_mode(a) +#define pmic_glb_flash_led_set_polarity(a) pmic_flash_led_set_polarity(a) +#define pmic_glb_spkr_add_right_left_chan pmic_spkr_add_right_left_chan(uint enable) +#define pmic_glb_spkr_en_stereo(a) pmic_spkr_en_stereo(a) +#define pmic_glb_vib_mot_set_volt(a) pmic_vib_mot_set_volt(a) +#define pmic_glb_vib_mot_set_mode(a) pmic_vib_mot_set_mode(a) +#define pmic_glb_vib_mot_set_polarity(a) pmic_vib_mot_set_polarity(a) +#define pmic_glb_vid_e(a)n pmic_vid_en(a) +#define pmic_glb_vid_load_detect_en(a) pmic_vid_load_detect_en(a) + +// Funtion declaration switching dependend on amss version +int pmic_glb_set_vreg(int enable, enum vreg_id id); +int pmic_glb_vreg_set_level(enum vreg_id id, unsigned millivolt); +int pmic_glb_power_down(void); +int pmic_glb_reset_chip(unsigned restart_reason); \ No newline at end of file