Merge "mmc: fix for cmd6 failure"
diff --git a/dev/pmic/pm8x41/include/pm8x41.h b/dev/pmic/pm8x41/include/pm8x41.h
new file mode 100644
index 0000000..411a063
--- /dev/null
+++ b/dev/pmic/pm8x41/include/pm8x41.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2012, 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, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ */
+
+#ifndef _PM8x41_H_
+#define _PM8x41_H_
+
+void pm8x41_set_boot_done();
+
+#endif
diff --git a/dev/pmic/pm8x41/include/pm8x41_hw.h b/dev/pmic/pm8x41/include/pm8x41_hw.h
new file mode 100644
index 0000000..36dd422
--- /dev/null
+++ b/dev/pmic/pm8x41/include/pm8x41_hw.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2012, 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, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ */
+
+#ifndef _PM8x41_HW_H_
+#define _PM8x41_HW_H_
+
+/* Slave IDs */
+#define PM8x41_SMBB_SLAVE_ID                  0
+
+/* Peripheral Base Addresses */
+#define PM8x41_SMBB_PERIPHERAL_ID_BASE        0x1600
+
+/* Register Offsets */
+#define SMBB_MISC_BOOT_DONE                   0x42
+#define BOOT_DONE_SHIFT                       7
+
+#endif
diff --git a/dev/pmic/pm8x41/pm8x41.c b/dev/pmic/pm8x41/pm8x41.c
new file mode 100644
index 0000000..d3b6cd1
--- /dev/null
+++ b/dev/pmic/pm8x41/pm8x41.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2012, 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, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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 <debug.h>
+#include <reg.h>
+#include <spmi.h>
+#include <pm8x41_hw.h>
+
+/* Function to set the boot done flag */
+void pm8x41_set_boot_done()
+{
+	struct pmic_arb_cmd cmd;
+	struct pmic_arb_param param;
+	uint8_t boot_done;
+
+	cmd.address = ((uint16_t)(PM8x41_SMBB_PERIPHERAL_ID_BASE) >> 8);
+	cmd.offset = SMBB_MISC_BOOT_DONE;
+	cmd.priority = 0;
+	cmd.slave_id = PM8x41_SMBB_SLAVE_ID;
+
+	/* Enable the module */
+	boot_done = 1 << BOOT_DONE_SHIFT;
+	param.buffer = &boot_done;
+	param.size = 1;
+
+	pmic_arb_write_cmd(&cmd,&param);
+
+}
diff --git a/dev/pmic/pm8x41/rules.mk b/dev/pmic/pm8x41/rules.mk
new file mode 100644
index 0000000..1c3bbc1
--- /dev/null
+++ b/dev/pmic/pm8x41/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += \
+	$(LOCAL_DIR)/pm8x41.o
diff --git a/platform/copper/include/platform/iomap.h b/platform/copper/include/platform/iomap.h
index 176cc2c..f29cccd 100644
--- a/platform/copper/include/platform/iomap.h
+++ b/platform/copper/include/platform/iomap.h
@@ -59,8 +59,12 @@
 #define MSM_USB_BASE                (PERIPH_SS_BASE + 0x00255000)
 
 #define CLK_CTL_BASE                0xFC400000
-#define TLMM_BASE_ADDR              0xFD500000
 
+#define SPMI_BASE                   0xFC4C0000
+#define SPMI_GENI_BASE              (SPMI_BASE + 0xA000)
+#define SPMI_PIC_BASE               (SPMI_BASE + 0xB000)
+
+#define TLMM_BASE_ADDR              0xFD500000
 #define GPIO_CONFIG_ADDR(x)         (TLMM_BASE_ADDR + 0x1000 + (x)*0x10)
 #define GPIO_IN_OUT_ADDR(x)         (TLMM_BASE_ADDR + 0x1004 + (x)*0x10)
 
diff --git a/platform/copper/include/platform/irqs.h b/platform/copper/include/platform/irqs.h
index 2f162b8..909c2c5 100644
--- a/platform/copper/include/platform/irqs.h
+++ b/platform/copper/include/platform/irqs.h
@@ -53,6 +53,8 @@
 /* Retrofit universal macro names */
 #define INT_USB_HS                             USB1_HS_IRQ
 
+#define EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ         (GIC_SPI_START + 190)
+
 #define NR_MSM_IRQS                            256
 #define NR_GPIO_IRQS                           173
 #define NR_BOARD_IRQS                          0
diff --git a/platform/msm8960/gpio.c b/platform/msm8960/gpio.c
index 7b3f808..c185ca6 100644
--- a/platform/msm8960/gpio.c
+++ b/platform/msm8960/gpio.c
@@ -129,6 +129,15 @@
 							 GPIO_8MA, GPIO_DISABLE);
 			break;
 
+		case GSBI_ID_8:
+			/* configure rx gpio */
+			gpio_tlmm_config(35, 1, GPIO_INPUT, GPIO_NO_PULL,
+							 GPIO_8MA, GPIO_DISABLE);
+			/* configure tx gpio */
+			gpio_tlmm_config(34, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+							 GPIO_8MA, GPIO_DISABLE);
+			break;
+
 		default:
 			ASSERT(0);
 		}
diff --git a/platform/msm_shared/include/spmi.h b/platform/msm_shared/include/spmi.h
new file mode 100644
index 0000000..d6a0b74
--- /dev/null
+++ b/platform/msm_shared/include/spmi.h
@@ -0,0 +1,140 @@
+/* Copyright (c) 2012, 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, Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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.
+ */
+
+#ifndef __SPMI_H
+#define __SPMI_H
+
+#define SPMI_MSM8974_MASTER_ID               0
+
+#define SPMI_GENI_REG(x)                     (SPMI_GENI_BASE + (x))
+#define SPMI_GENI_CFG_REG_BASE               SPMI_GENI_REG(0x100)
+#define SPMI_GENI_CFG_RAM_BASE               SPMI_GENI_REG(0x200)
+
+#define SPMI_GENI_CFG_REGn(x)                (SPMI_GENI_CFG_REG_BASE + 4 * (x))
+#define SPMI_GENI_CFG_RAM_REGn(x)            (SPMI_GENI_CFG_RAM_BASE + 4 * (x))
+
+#define SPMI_GENI_CLK_CTRL_REG               SPMI_GENI_REG(0x00)
+#define SPMI_GENI_OUTPUT_CTRL_REG            SPMI_GENI_REG(0x10)
+#define SPMI_GENI_FORCE_DEFAULT_REG          SPMI_GENI_REG(0x0C)
+#define SPMI_MID_REG                         SPMI_GENI_REG(0xF00)
+#define SPMI_CFG_REG                         SPMI_GENI_REG(0xF04)
+#define SPMI_SEC_DISABLE_REG                 SPMI_GENI_REG(0xF08)
+
+#define SPMI_GENI_IRQ_ENABLE                 (SPMI_GENI_BASE + 0x24)
+#define SPMI_GENI_IRQ_CLEAR                  (SPMI_GENI_BASE + 0x28)
+#define SPMI_GENI_TX_FIFO_BASE               (SPMI_GENI_BASE + 0x40)
+#define SPMI_GENI_RX_FIFO_BASE               (SPMI_GENI_BASE + 0x80)
+
+#define SPMI_GENI_TX_FIFOn(x)                (SPMI_GENI_TX_FIFO_BASE + 4 * (x))
+#define SPMI_GENI_RX_FIFOn(x)                (SPMI_GENI_RX_FIFO_BASE + 4 * (x))
+
+#define PMIC_ARB_CHNLn_CMD0(x)               (SPMI_BASE + 0xF800 + (x) * 0x80)
+#define PMIC_ARB_CMD_OPCODE_SHIFT            27
+#define PMIC_ARB_CMD_PRIORITY_SHIFT          26
+#define PMIC_ARB_CMD_SLAVE_ID_SHIFT          20
+#define PMIC_ARB_CMD_ADDR_SHIFT              12
+#define PMIC_ARB_CMD_ADDR_OFFSET_SHIFT       4
+#define PMIC_ARB_CMD_BYTE_CNT_SHIFT          0
+
+#define PMIC_ARB_CHNLn_CONFIG(x)             (SPMI_BASE + 0xF804 + (x) * 0x80)
+#define PMIC_ARB_CHNLn_STATUS(x)             (SPMI_BASE + 0xF808 + (x) * 0x80)
+#define PMIC_ARB_CHNLn_WDATA(x, n)           (SPMI_BASE + 0xF810 + \
+	(x) * 0x80 + (n) * 4)
+#define PMIC_ARB_CHNLn_RDATA(x,n)            (SPMI_BASE + 0xF818 + \
+	(x) * 0x80 + (n) * 4)
+
+/* PIC Registers */
+#define SPMI_PIC_OWNERm_ACC_STATUSn(m, n)    (SPMI_PIC_BASE + 32 * (m) + 4 * (n))
+#define SPMI_PIC_ACC_ENABLEn(n)              (SPMI_PIC_BASE + 0x200 + 4 * (n))
+#define SPMI_PIC_IRQ_STATUSn(n)              (SPMI_PIC_BASE + 0x600 + 0x4 * (n))
+#define SPMI_PIC_IRQ_CLEARn(n)               (SPMI_PIC_BASE + 0xA00 + 0x4 * (n))
+
+/* SPMI Commands */
+#define SPMI_CMD_EXT_REG_WRTIE_LONG          0x00
+#define SPMI_CMD_EXT_REG_READ_LONG           0x01
+#define SPMI_CMD_EXT_REG_READ_LONG_DELAYED   0x02
+#define SPMI_CMD_TRANSFER_BUS_OWNERSHIP      0x03
+
+/* The commands below are not yet supported */
+#define SPMI_CMD_RESET                       0x04
+#define SPMI_CMD_SLEEP                       0x05
+#define SPMI_CMD_SHUTDOWN                    0x06
+#define SPMI_CMD_WAKEUP                      0x07
+#define SPMI_CMD_EXT_REG_WRITE               0x08
+#define SPMI_CMD_EXT_REG_READ                0x09
+#define SPMI_CMD_REG_WRITE                   0x0A
+#define SPMI_CMD_REG_READ                    0x0B
+#define SPMI_CMD_REG_0_WRITE                 0x0C
+#define SPMI_CMD_AUTH                        0x0D
+#define SPMI_CMD_MASTER_WRITE                0x0E
+#define SPMI_CMD_MASTER_READ                 0x0F
+#define SPMI_CMD_DEV_DESC_BLK_MASTER_READ    0x10
+#define SPMI_CMD_DEV_DESC_BLK_SLAVE_READ     0x11
+
+enum spmi_geni_cmd_return_value{
+	SPMI_CMD_DONE,
+	SMPI_CMD_DENIED,
+	SPMI_CMD_FAILURE,
+	SPMI_ILLEGAL_CMD,
+	SPMI_CMD_OVERRUN = 6,
+	SPMI_TX_FIFO_RD_ERR,
+	SPMI_TX_FIFO_WR_ERR,
+	SPMI_RX_FIFO_RD_ERR,
+	SPMI_RX_FIFO_WR_ERR
+};
+
+enum pmic_arb_chnl_return_values{
+	PMIC_ARB_CMD_DONE,
+	PMIC_ARB_CMD_FAILURE,
+	PMIC_ARB_CMD_DENIED,
+	PMIC_ARB_CMD_DROPPED,
+};
+
+struct pmic_arb_cmd{
+	uint8_t opcode;
+	uint8_t priority;
+	uint8_t slave_id;
+	uint8_t address;
+	uint8_t offset;
+	uint8_t byte_cnt;
+};
+
+struct pmic_arb_param{
+	uint8_t *buffer;
+	uint8_t size;
+};
+
+typedef void (*spmi_callback)();
+
+void spmi_init(uint32_t, uint32_t);
+unsigned int pmic_arb_write_cmd(struct pmic_arb_cmd *cmd,
+	struct pmic_arb_param *param);
+unsigned int pmic_arb_read_cmd(struct pmic_arb_cmd *cmd,
+	struct pmic_arb_param *param);
+
+#endif
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 8abd230..a7f6c93 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -65,7 +65,8 @@
 			$(LOCAL_DIR)/clock.o \
 			$(LOCAL_DIR)/clock_pll.o \
 			$(LOCAL_DIR)/clock_lib2.o \
-			$(LOCAL_DIR)/uart_dm.o
+			$(LOCAL_DIR)/uart_dm.o \
+			$(LOCAL_DIR)/spmi.o
 endif
 
 ifeq ($(PLATFORM),msm7x27a)
diff --git a/platform/msm_shared/spmi.c b/platform/msm_shared/spmi.c
new file mode 100644
index 0000000..b361a30
--- /dev/null
+++ b/platform/msm_shared/spmi.c
@@ -0,0 +1,317 @@
+/* Copyright (c) 2012, 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, Inc. nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * 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 <debug.h>
+#include <reg.h>
+#include <spmi.h>
+#include <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/interrupts.h>
+
+static uint32_t pmic_arb_chnl_num;
+static uint32_t pmic_arb_owner_id;
+static uint8_t pmic_irq_perph_id;
+static spmi_callback callback;
+
+/* Function to initialize SPMI controller.
+ * chnl_num : Channel number to be used by this EE.
+ */
+void spmi_init(uint32_t chnl_num, uint32_t owner_id)
+{
+	/* Initialize PMIC Arbiter Channel Number */
+	pmic_arb_chnl_num = chnl_num;
+	pmic_arb_owner_id = owner_id;
+}
+
+static void write_wdata_from_array(uint8_t *array,
+	                               uint8_t reg_num,
+	                               uint8_t array_size,
+	                               uint8_t* bytes_written)
+{
+	uint32_t shift_value[] = {0, 8, 16, 24};
+	int i;
+	int j;
+	uint32_t val = 0;
+
+	/* Write to WDATA */
+	for (i = 0; (*bytes_written < array_size) && (i < 4); i++)
+	{
+		val |= (uint32_t)(array[*bytes_written]) << shift_value[i];
+		(*bytes_written)++;
+	}
+
+	writel(val, PMIC_ARB_CHNLn_WDATA(pmic_arb_chnl_num, reg_num));
+}
+
+
+/* Initiate a write cmd by writing to cmd register.
+ * Commands are written according to cmd parameters
+ * cmd->opcode   : SPMI opcode for the command
+ * cmd->priority : Priority of the command
+ *                 High priority : 1
+ *                 Low Priority : 0
+ * cmd->address  : SPMI Peripheral Address.
+ * cmd->offset   : Offset Address for the command.
+ * cmd->bytecnt  : Number of bytes to be written.
+ *
+ * param is the parameter to the command
+ * param->buffer : Value to be written
+ * param->size   : Size of the buffer.
+ *
+ * return value : 0 if success, the error bit set on error
+ */
+unsigned int pmic_arb_write_cmd(struct pmic_arb_cmd *cmd,
+                                struct pmic_arb_param *param)
+{
+	uint32_t bytes_written = 0;
+	uint32_t error;
+	uint32_t val = 0;
+
+	/* Disable IRQ mode for the current channel*/
+	writel(0x0, PMIC_ARB_CHNLn_CONFIG(pmic_arb_chnl_num));
+
+	/* Write parameters for the cmd */
+	if (cmd == NULL)
+	{
+		dprintf(CRITICAL,"PMIC arbiter error, no command provided\n");
+		return 1;
+	}
+
+	/* Write the data bytes according to the param->size
+	 * Can write upto 8 bytes.
+	 */
+
+	/* Write first 4 bytes to WDATA0 */
+	write_wdata_from_array(param->buffer, 0, param->size, &bytes_written);
+
+	if (bytes_written < param->size)
+	{
+		/* Write next 4 bytes to WDATA1 */
+		write_wdata_from_array(param->buffer, 1, param->size, &bytes_written);
+	}
+
+	/* Fill in the byte count for the command
+	 * Note: Byte count is one less than the number of bytes transferred.
+	 */
+	cmd->byte_cnt = param->size - 1;
+	/* Fill in the Write cmd opcode. */
+	cmd->opcode = SPMI_CMD_EXT_REG_WRTIE_LONG;
+
+	/* Write the command */
+	val = 0;
+	val |= ((uint32_t)(cmd->opcode) << PMIC_ARB_CMD_OPCODE_SHIFT);
+	val |= ((uint32_t)(cmd->priority) << PMIC_ARB_CMD_PRIORITY_SHIFT);
+	val |= ((uint32_t)(cmd->slave_id) << PMIC_ARB_CMD_SLAVE_ID_SHIFT);
+	val |= ((uint32_t)(cmd->address) << PMIC_ARB_CMD_ADDR_SHIFT);
+	val |= ((uint32_t)(cmd->offset) << PMIC_ARB_CMD_ADDR_OFFSET_SHIFT);
+	val |= ((uint32_t)(cmd->byte_cnt));
+
+	writel(val, PMIC_ARB_CHNLn_CMD0(pmic_arb_chnl_num));
+
+	/* Wait till CMD DONE status */
+	while (!(val = readl(PMIC_ARB_CHNLn_STATUS(pmic_arb_chnl_num))));
+
+	/* Check for errors */
+	error = val ^ (1 << PMIC_ARB_CMD_DONE);
+	if (error)
+	{
+		dprintf(CRITICAL, "SPMI write command failure: \
+			cmd_id = %u, error = %u\n", cmd->opcode, error);
+		return error;
+	}
+	else
+		return 0;
+}
+
+static void read_rdata_into_array(uint8_t *array,
+                                  uint8_t reg_num,
+                                  uint8_t array_size,
+                                  uint8_t* bytes_read)
+{
+	uint32_t val = 0;
+	uint32_t mask_value[] = {0xFF, 0xFF00, 0xFF0000, 0xFF000000};
+	uint8_t shift_value[] = {0, 8, 16, 24};
+	int i;
+
+	val = readl(PMIC_ARB_CHNLn_RDATA(pmic_arb_chnl_num, reg_num));
+
+	/* Read at most 4 bytes */
+	for (i = 0; (i < 4) && (*bytes_read < array_size); i++)
+	{
+		array[*bytes_read] = (val & mask_value[i]) >> shift_value[i];
+		(*bytes_read)++;
+	}
+}
+
+/* Initiate a read cmd by writing to cmd register.
+ * Commands are written according to cmd parameters
+ * cmd->opcode   : SPMI opcode for the command
+ * cmd->priority : Priority of the command
+ *                 High priority : 1
+ *                 Low Priority : 0
+ * cmd->address  : SPMI Peripheral Address.
+ * cmd->offset   : Offset Address for the command.
+ * cmd->bytecnt  : Number of bytes to be read.
+ *
+ * param is the buffer to the save command data.
+ * param->buffer : Buffer to store the bytes returned.
+ * param->size   : Size of the buffer.
+ *
+ * return value : 0 if success, the error bit set on error
+ */
+unsigned int pmic_arb_read_cmd(struct pmic_arb_cmd *cmd,
+                               struct pmic_arb_param *param)
+{
+	uint32_t val = 0;
+	uint32_t error;
+	uint32_t addr;
+	uint8_t bytes_read = 0;
+
+	/* Disable IRQ mode for the current channel*/
+	writel(0x0, PMIC_ARB_CHNLn_CONFIG(pmic_arb_chnl_num));
+
+	/* Fill in the byte count for the command
+	 * Note: Byte count is one less than the number of bytes transferred.
+	 */
+	cmd->byte_cnt = param->size - 1;
+	/* Fill in the Write cmd opcode. */
+	cmd->opcode = SPMI_CMD_EXT_REG_READ_LONG;
+
+	val |= ((uint32_t)(cmd->opcode) << PMIC_ARB_CMD_OPCODE_SHIFT);
+	val |= ((uint32_t)(cmd->priority) << PMIC_ARB_CMD_PRIORITY_SHIFT);
+	val |= ((uint32_t)(cmd->slave_id) << PMIC_ARB_CMD_SLAVE_ID_SHIFT);
+	val |= ((uint32_t)(cmd->address) << PMIC_ARB_CMD_ADDR_SHIFT);
+	val |= ((uint32_t)(cmd->offset) << PMIC_ARB_CMD_ADDR_OFFSET_SHIFT);
+	val |= ((uint32_t)(cmd->byte_cnt));
+
+	writel(val, PMIC_ARB_CHNLn_CMD0(pmic_arb_chnl_num));
+
+	/* Wait till CMD DONE status */
+	while (!(val = readl(PMIC_ARB_CHNLn_STATUS(pmic_arb_chnl_num))));
+
+	/* Check for errors */
+	error = val ^ (1 << PMIC_ARB_CMD_DONE);
+
+	if (error)
+	{
+		dprintf(CRITICAL, "SPMI read command failure: \
+			cmd_id = %u, error = %u\n", cmd->opcode, error);
+		return error;
+	}
+
+	/* Read the RDATA0 */
+	read_rdata_into_array(param->buffer, 0, param->size , &bytes_read);
+
+	if (bytes_read < param->size)
+	{
+		/* Read the RDATA1 */
+		read_rdata_into_array(param->buffer, 1, param->size , &bytes_read);
+
+	}
+
+	if (bytes_read < param->size)
+	{
+		/* Read the RDATA2 */
+		read_rdata_into_array(param->buffer, 2, param->size , &bytes_read);
+
+	}
+
+	return 0;
+}
+
+
+/* Funtion to determine if the peripheral that caused the interrupt
+ * is of interest.
+ * Also handles callback function and interrupt clearing if the
+ * correct interrupt is fired.
+ * periph_acc_irq: SPMI_PIC_OWNERm_ACC_STATUSn register id.
+ * status: Bits of the periph_acc_irq.
+ * return 1 if the peripheral is of interest,
+ * 0 otherwise.
+ */
+int spmi_acc_irq(uint32_t periph_acc_irq, uint32_t status)
+{
+	uint8_t reg_id;
+	uint8_t offset;
+
+	/* Narrow down the correct register for the peripheral*/
+	reg_id = pmic_irq_perph_id / 32;
+	if (periph_acc_irq * 8 != reg_id)
+		return 0;
+
+	/* Narrow down the correct interrupt within the register */
+	offset = pmic_irq_perph_id & 31;
+	if ((status & offset))
+	{
+		/* Clear the interrupt */
+		writel(offset ^ status, SPMI_PIC_IRQ_CLEARn(reg_id));
+
+		/* Confirm that the interrupt has been cleared */
+		while(readl(SPMI_PIC_IRQ_STATUSn(reg_id)) & offset);
+
+		/* Call the callback */
+		callback();
+		return 1;
+	}
+	else
+		return 0;
+}
+
+void spmi_irq()
+{
+	int i;
+	uint32_t status;
+
+	/* Go through the Peripheral list to figure out the periperal
+	 * that caused the interrupt
+	 */
+	for (i = 0; i < 8; i++)
+	{
+		status = readl(SPMI_PIC_OWNERm_ACC_STATUSn(pmic_arb_owner_id, i));
+		if (status)
+			if (!spmi_acc_irq(i, status))
+				/* Not the correct interrupt, continue to wait */
+				return;
+	}
+	mask_interrupt(EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ);
+}
+
+/* Enable interrupts on a particular peripheral: periph_id */
+void spmi_enable_periph_interrupts(uint8_t periph_id)
+{
+	pmic_irq_perph_id = periph_id;
+
+	register_int_handler(EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ , spmi_irq, 0);
+	unmask_interrupt(EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ);
+
+}
+
+void spmi_uninit()
+{
+	mask_interrupt(EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ);
+}
diff --git a/target/copper/init.c b/target/copper/init.c
index 2630ad1..a2f3f14 100644
--- a/target/copper/init.c
+++ b/target/copper/init.c
@@ -35,13 +35,17 @@
 #include <platform.h>
 #include <uart_dm.h>
 #include <mmc.h>
+#include <spmi.h>
+
 
 static unsigned int target_id;
-extern void dmb(void);
 
 static void target_detect(void);
 
-#define COPPER_TARGET_ID        3999
+#define COPPER_TARGET_ID        0xffffffff
+#define PMIC_ARB_CHANNEL_NUM    0
+#define PMIC_ARB_OWNER_ID       0
+
 
 static uint32_t mmc_sdc_base[] =
 	{ MSM_SDC1_BASE, MSM_SDC2_BASE, MSM_SDC3_BASE, MSM_SDC4_BASE };
@@ -60,6 +64,7 @@
 	dprintf(INFO, "target_init()\n");
 
 	target_id = COPPER_TARGET_ID;
+	spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
 
 	/* Trying Slot 1*/
 	slot = 1;
diff --git a/target/copper/rules.mk b/target/copper/rules.mk
index b6eba33..0f6a21f 100644
--- a/target/copper/rules.mk
+++ b/target/copper/rules.mk
@@ -16,7 +16,8 @@
 
 MODULES += \
 	dev/keys \
-    lib/ptable
+    lib/ptable \
+	dev/pmic/pm8x41
 
 DEFINES += \
 	MEMSIZE=$(MEMSIZE) \
diff --git a/target/msm8960/init.c b/target/msm8960/init.c
index b803f32..c87652a 100644
--- a/target/msm8960/init.c
+++ b/target/msm8960/init.c
@@ -255,7 +255,14 @@
 	case LINUX_MACHTYPE_8960_APQ:
 	case LINUX_MACHTYPE_8960_LIQUID:
 
-		uart_dm_init(5, 0x16400000, 0x16440000);
+		if(board_baseband() == BASEBAND_SGLTE)
+		{
+			uart_dm_init(8, 0x1A000000, 0x1A040000);;
+		}
+		else
+		{
+			uart_dm_init(5, 0x16400000, 0x16440000);
+		}
 		break;
 
 	case LINUX_MACHTYPE_8930_CDP: