| /* Copyright Statement: |
| * |
| * This software/firmware and related documentation ("MediaTek Software") are |
| * protected under relevant copyright laws. The information contained herein is |
| * confidential and proprietary to MediaTek Inc. and/or its licensors. Without |
| * the prior written permission of MediaTek inc. and/or its licensors, any |
| * reproduction, modification, use or disclosure of MediaTek Software, and |
| * information contained herein, in whole or in part, shall be strictly |
| * prohibited. |
| * |
| * MediaTek Inc. (C) 2019. All rights reserved. |
| * |
| * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER |
| * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL |
| * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR |
| * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH |
| * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, |
| * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES |
| * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. |
| * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO |
| * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK |
| * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE |
| * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
| * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S |
| * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE |
| * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE |
| * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE |
| * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| * |
| * The following software/firmware and/or related documentation ("MediaTek |
| * Software") have been modified by MediaTek Inc. All revisions are subject to |
| * any receiver's applicable license agreements with MediaTek Inc. |
| */ |
| /* |
| * MTK SPMI Driver |
| * |
| * Copyright 2018 MediaTek Co.,Ltd. |
| * |
| * DESCRIPTION: |
| * This file provides API for other drivers to access PMIC registers |
| * |
| */ |
| |
| #include <spmi.h> |
| #include <pmif.h> |
| #include <pmif_sw.h> |
| #include <spmi_sw.h> |
| #include <mt6315_upmu_hw.h> |
| |
| static int mt6885_spmi_regs[] = { |
| [SPMI_OP_ST_CTRL] = 0x0000, |
| [SPMI_GRP_ID_EN] = 0x0004, |
| [SPMI_OP_ST_STA] = 0x0008, |
| [SPMI_MST_SAMPL] = 0x000c, |
| [SPMI_MST_REQ_EN] = 0x0010, |
| #if SPMI_RCS_SUPPORT |
| [SPMI_RCS_CTRL] = 0x0014, |
| [SPMI_SLV_3_0_EINT] = 0x0020, |
| [SPMI_SLV_7_4_EINT] = 0x0024, |
| [SPMI_SLV_B_8_EINT] = 0x0028, |
| [SPMI_SLV_F_C_EINT] = 0x002c, |
| #endif /* #if SPMI_RCS_SUPPORT */ |
| [SPMI_REC_CTRL] = 0x0040, |
| [SPMI_REC0] = 0x0044, |
| [SPMI_REC1] = 0x0048, |
| [SPMI_REC2] = 0x004c, |
| [SPMI_REC3] = 0x0050, |
| [SPMI_REC4] = 0x0054, |
| #if SPMI_RCS_SUPPORT |
| [SPMI_REC_CMD_DEC] = 0x005c, |
| [SPMI_DEC_DBG] = 0x00f8, |
| #endif |
| [SPMI_MST_DBG] = 0x00fc, |
| }; |
| |
| static struct pmif *pmif_spmi_arb_ctrl[SPMI_MASTER_MAX]; |
| #if MT63xx_EVB |
| #if defined(MT6885) || defined(MT6873) |
| struct spmi_device spmi_dev[] = { |
| { |
| .slvid = SPMI_SLAVE_3, |
| .grpiden = 0x800, |
| .type = BUCK_MD, |
| .type_id = BUCK_MD_ID, |
| .mstid = SPMI_MASTER_0,/* spmi-m */ |
| .hwcid_addr = 0x09, |
| .hwcid_val = 0x15, |
| .swcid_addr = 0x0b, |
| .swcid_val = 0x15, |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_6, |
| .grpiden = 0x800, |
| .type = BUCK_CPU, |
| .type_id = BUCK_CPU_ID, |
| .mstid = SPMI_MASTER_0,/* spmi-m */ |
| .hwcid_addr = 0x09, |
| .hwcid_val = 0x15, |
| .swcid_addr = 0x0b, |
| .swcid_val = 0x15, |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_7, |
| .grpiden = 0x800, |
| .type = BUCK_GPU, |
| .type_id = BUCK_GPU_ID, |
| .mstid = SPMI_MASTER_0,/* spmi-m */ |
| .hwcid_addr = 0x09, |
| .hwcid_val = 0x15, |
| .swcid_addr = 0x0b, |
| .swcid_val = 0x15, |
| .pmif_arb = NULL, |
| }, |
| }; |
| #elif defined(MT6853) |
| #if defined(MT6315) |
| struct spmi_device spmi_dev[] = { |
| { |
| .slvid = SPMI_SLAVE_3, |
| .grpiden = 0x800, |
| .type = BUCK_MD, |
| .type_id = BUCK_MD_ID, |
| .mstid = SPMI_MASTER_1,/* spmi-m */ |
| .hwcid_addr = 0x09, |
| .hwcid_val = 0x15, |
| .swcid_addr = 0x0b, |
| .swcid_val = 0x15, |
| .pmif_arb = NULL, |
| }, |
| }; |
| #else |
| struct spmi_device spmi_dev[] = { |
| { |
| .slvid = SPMI_SLAVE_9, |
| .grpiden = 0x0, |
| .type = SUB_PMIC, |
| .type_id = SUB_PMIC_ID, |
| .mstid = SPMI_MASTER_1,/* spmi-m */ |
| .hwcid_addr = 0x0000, |
| .hwcid_val = 0x70,/* check [7:4] */ |
| .swcid_addr = 0x0001, |
| .swcid_val = 0x08,/* check [3:0] */ |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_8, |
| .grpiden = 0x0, |
| .type = BUCK_MD, |
| .type_id = BUCK_MD_ID, |
| .mstid = SPMI_MASTER_P_1, /* spmi-p */ |
| .hwcid_addr = 0x0706, |
| .hwcid_val = 0x00, |
| .swcid_addr = 0x0706, |
| .swcid_val = 0x00, |
| .pmif_arb = NULL, |
| }, |
| }; |
| #endif |
| #elif defined(CHIP10992) |
| struct spmi_device spmi_dev[] = { |
| { |
| .slvid = SPMI_SLAVE_4, |
| .grpiden = 0x1 << 0xB, |
| .type = MAIN_PMIC, |
| .type_id = MAIN_PMIC_ID, |
| .mstid = SPMI_MASTER_1,/* spmi-m */ |
| .hwcid_addr = 0x09, |
| .hwcid_val = 0x30, |
| .swcid_addr = 0x0b, |
| .swcid_val = 0x30, |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_4, |
| .grpiden = 0x1 << 0xB, |
| .type = BUCK_MD, |
| .type_id = BUCK_MD_ID, |
| .mstid = SPMI_MASTER_P_1,/* spmi-p */ |
| .hwcid_addr = 0x01A0, /* TOP_VRCTL_VR0_EN */ |
| .hwcid_val = 0xFF, /* All BUCK EN = 0xFF */ |
| .pmif_arb = NULL, |
| }, |
| }; |
| #endif /* end of #if defined(MT6885) || defined(MT6873) */ |
| #else |
| struct spmi_device spmi_dev[] = { |
| { |
| .slvid = SPMI_SLAVE_12, |
| .grpiden = 0x100, |
| .type = BUCK_MD, |
| .type_id = BUCK_MD_ID, |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_10, |
| .grpiden = 0x100, |
| .type = BUCK_CPU, |
| .type_id = BUCK_CPU_ID, |
| .pmif_arb = NULL, |
| }, { |
| .slvid = SPMI_SLAVE_11, |
| .grpiden = 0x100, |
| .type = BUCK_GPU, |
| .type_id = BUCK_GPU_ID, |
| .pmif_arb = NULL, |
| }, |
| }; |
| #endif |
| unsigned char spmi_device_cnt; |
| |
| /* spmi internal API declaration */ |
| static int spmi_config_master(unsigned int mstid, kal_bool en); |
| static int spmi_config_slave(struct spmi_device *dev); |
| static int spmi_cali_rd_clock_polarity(struct spmi_device *dev, |
| unsigned int mstid); |
| static int spmi_ctrl_op_st(int mstid, unsigned int grpiden, |
| unsigned int sid, unsigned int cmd); |
| #if SPMI_RCS_SUPPORT |
| static int spmi_enable_rcs(struct spmi_device *dev, unsigned int mstid); |
| int spmi_read_eint_sta(unsigned char *slv_eint_sta); |
| #endif |
| #if SPMI_DEBUG |
| static int spmi_rw_test(struct spmi_device *dev); |
| static int spmi_read_check(struct spmi_device *dev); |
| static int spmi_drv_ut(struct spmi_device *dev, unsigned int ut); |
| #endif |
| int spmi_enable_group_id(int mstid, unsigned int grpiden); |
| int spmi_lock_slave_reg(struct spmi_device *dev); |
| int spmi_unlock_slave_reg(struct spmi_device *dev); |
| |
| #if SPMI_NO_PMIC |
| int spmi_init(struct pmif *pmif_arb) |
| { |
| SPMI_INFO("do Nothing.\n"); |
| return 0; |
| } |
| |
| #else /* #ifdef SPMI_NO_PMIC */ |
| /* |
| * Function : mtk_spmi_readl() |
| * Description : mtk spmi controller read api |
| * Parameter : |
| * Return : |
| */ |
| unsigned int spmi_readl(int mstid, enum spmi_regs reg) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| |
| return DRV_Reg32(arb->spmimst_base + arb->spmimst_regs[reg]); |
| } |
| |
| /* |
| * Function : mtk_spmi_writel() |
| * Description : mtk spmi controller write api |
| * Parameter : |
| * Return : |
| */ |
| void spmi_writel(int mstid, enum spmi_regs reg, unsigned int val) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| |
| DRV_WriteReg32(arb->spmimst_base + arb->spmimst_regs[reg], val); |
| } |
| |
| /* |
| * Function : spmi_lock_slave_reg() |
| * Description : protect spmi slv register to be write |
| * Parameter : |
| * Return : |
| */ |
| int spmi_lock_slave_reg(struct spmi_device *dev) |
| { |
| const unsigned char wpk_key = 0x0; |
| const unsigned char wpk_key_h = 0x0; |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* enable dig_wpk key, write 0x0*/ |
| spmi_ext_register_writel(dev, MT6315_PMIC_DIG_WPK_KEY_ADDR, |
| &wpk_key, 1); |
| spmi_ext_register_writel(dev, MT6315_PMIC_DIG_WPK_KEY_H_ADDR, |
| &wpk_key_h, 1); |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Function : spmi_unlock_slave_reg() |
| * Description : unlock spmi slv register to write |
| * Parameter : |
| * Return : |
| */ |
| int spmi_unlock_slave_reg(struct spmi_device *dev) |
| { |
| const unsigned char wpk_key = 0x15; |
| const unsigned char wpk_key_h = 0x63; |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* disable dig_wpk key, write 0x6315*/ |
| spmi_ext_register_writel(dev, MT6315_PMIC_DIG_WPK_KEY_ADDR, |
| &wpk_key, 1); |
| spmi_ext_register_writel(dev, MT6315_PMIC_DIG_WPK_KEY_H_ADDR, |
| &wpk_key_h, 1); |
| } |
| |
| return 0; |
| } |
| |
| static int spmi_config_master(unsigned int mstid, kal_bool en) |
| { |
| /* Software reset */ |
| DRV_WriteReg32(WDT_SWSYSRST2, 0x85 << 24 | 0x1 << 4); |
| |
| #if !defined(CONFIG_FPGA_EARLY_PORTING) |
| /* TBD */ |
| DRV_WriteReg32(CLK_CFG_16_CLR, 0x7 | (0x1 << 4) | (0x1 << 7)); |
| DRV_WriteReg32(CLK_CFG_UPDATE2, 0x1 << 2); |
| #endif |
| |
| /* Software reset */ |
| DRV_WriteReg32(WDT_SWSYSRST2, 0x85 << 24); |
| |
| /* Enable SPMI */ |
| spmi_writel(mstid, SPMI_MST_REQ_EN, en); |
| |
| SPMI_INFO("%s done\n", __func__); |
| |
| return 0; |
| } |
| |
| static int spmi_config_slave(struct spmi_device *dev) |
| { |
| return 0; |
| } |
| |
| static int spmi_cali_rd_clock_polarity(struct spmi_device *dev, |
| unsigned int mstid) |
| { |
| unsigned int i = 0; |
| #if 0 //TBD |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #endif |
| struct cali cali_data[] = { |
| {SPMI_CK_DLY_1T, SPMI_CK_POL_POS}, |
| {SPMI_CK_NO_DLY, SPMI_CK_POL_POS}, |
| {SPMI_CK_NO_DLY, SPMI_CK_POL_NEG} |
| }; |
| |
| /* Indicate sampling clock polarity, 1: Positive 0: Negative */ |
| for (i = 0;i < 3; i++) { |
| spmi_writel(mstid, SPMI_MST_SAMPL, |
| (cali_data[i].dly << 0x1) | cali_data[i].pol); |
| /* for exception reboot, we only call UT/spmi_read_check w/o |
| * write test. It avoid to affect exception record. |
| */ |
| #if SPMI_DEBUG |
| if (spmi_read_check(dev) == 0) { |
| SPMI_DBG("dly:%d, pol:%d\n", cali_data[i].dly, |
| cali_data[i].pol); |
| break; |
| } |
| #endif |
| } |
| if (i == 3) { |
| SPMI_ERR("FATAL ERROR"); |
| ASSERT(0); |
| } |
| |
| #if 0 //TBD |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #endif |
| return 0; |
| } |
| |
| #if SPMI_RCS_SUPPORT |
| static int spmi_enable_rcs(struct spmi_device *dev, unsigned int mstid) |
| { |
| unsigned char wdata = 0, rdata = 0, i = 0; |
| |
| /* clear int status */ |
| wdata = 0xc0; |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_INT_STATUS_RCS0_ADDR, |
| &wdata, 1); |
| |
| /* config match mode */ |
| wdata = 0x2; |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_INT_RCS1_ADDR, &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_INT_RCS1_ADDR, &rdata, 1); |
| SPMI_DBG("slvid:%x After set RG_INT_RCS1[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_INT_RCS1_ADDR, rdata); |
| |
| /* set |
| * RG_RCS_ABIT[1] = 1 |
| * RG_RCS_CMD[3:2] = 1 |
| * RG_RCS_ID[7:4] = 0 |
| */ |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_RCS_ABIT_ADDR, &rdata, 1); |
| wdata = rdata | |
| (0x1 << MT6315_PMIC_RG_RCS_ABIT_SHIFT) | |
| (0x1 << MT6315_PMIC_RG_RCS_CMD_SHIFT); |
| wdata &= ~(0xf << MT6315_PMIC_RG_RCS_ID_SHIFT); |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_RCS_ABIT_ADDR, &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_RCS_ABIT_ADDR, &rdata, 1); |
| SPMI_DBG("slvid:%x After set SPMI_RCS_FUN0[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_RCS_ABIT_ADDR, rdata); |
| |
| /* set rcs_addr = slvid */ |
| wdata = dev->slvid; |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_RCS_ADDR_ADDR, &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_RCS_ADDR_ADDR, &rdata, 1); |
| SPMI_DBG("slvid:%x After set RCS_ADDR[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_RCS_ADDR_ADDR, rdata); |
| |
| /* set mask */ |
| wdata = 0x0; |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_INT_MASK_RCS0_ADDR, |
| &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_INT_MASK_RCS0_ADDR, |
| &rdata, 1); |
| SPMI_DBG("slvid:%x After set RG_INT_MASK[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_INT_MASK_RCS0_ADDR, rdata); |
| |
| /* set top rcs0/rcs1 interrupt enable */ |
| wdata = (0x1 << MT6315_PMIC_RG_INT_EN_RCS0_SHIFT) | |
| (0x1 << MT6315_PMIC_RG_INT_EN_RCS1_SHIFT); |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_INT_EN_RCS0_ADDR, |
| &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_INT_EN_RCS0_ADDR, |
| &rdata, 1); |
| SPMI_DBG("slvid:%x After set RG_INT_EN[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_INT_EN_RCS0_ADDR, rdata); |
| |
| /* enable rcs function */ |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_RCS_ENABLE_ADDR, |
| &rdata, 1); |
| wdata = rdata | (0x1 << MT6315_PMIC_RG_RCS_ENABLE_SHIFT); |
| spmi_ext_register_writel(dev, MT6315_PMIC_RG_RCS_ENABLE_ADDR, |
| &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_RG_RCS_ENABLE_ADDR, |
| &rdata, 1); |
| SPMI_DBG("slvid:%x After set Enable[0x%x]=0x%x\n", dev->slvid, |
| MT6315_PMIC_RG_RCS_ENABLE_ADDR, rdata); |
| |
| } |
| |
| int spmi_read_eint_sta(unsigned char *slv_eint_sta) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, SPMI_MASTER_0); |
| unsigned char offset = 0, j = 0, rdata = 0; |
| unsigned int regs = 0; |
| |
| for (offset = 0; offset < 4; offset++) { |
| regs = arb->spmimst_regs[SPMI_SLV_3_0_EINT] + (offset*4); |
| rdata = DRV_Reg32(arb->spmimst_base + regs); |
| *(slv_eint_sta + j) = rdata & 0xff; |
| *(slv_eint_sta + j+1) = (rdata >> 8) & 0xff; |
| *(slv_eint_sta + j+2) = (rdata >> 16) & 0xff; |
| *(slv_eint_sta + j+3) = (rdata >> 24) & 0xff; |
| j += 4; |
| } |
| |
| for (offset = 0; offset < 16; offset++) { |
| SPMI_INFO("%d, slv_eint_sta[0x%x]\n", offset, |
| *(slv_eint_sta + offset)); |
| } |
| spmi_writel(mstid, SPMI_SLV_3_0_EINT, 0xffffffff); |
| spmi_writel(mstid, SPMI_SLV_7_4_EINT, 0xffffffff); |
| spmi_writel(mstid, SPMI_SLV_B_8_EINT, 0xffffffff); |
| spmi_writel(mstid, SPMI_SLV_F_C_EINT, 0xffffffff); |
| |
| SPMI_INFO("%s, [0x%x]=0x%x\n", __func__, |
| arb->spmimst_base + arb->spmimst_regs[SPMI_DEC_DBG], |
| spmi_readl(mstid, SPMI_DEC_DBG)); |
| } |
| #endif |
| |
| #if SPMI_EXTADDR_SUPPORT |
| int spmi_register_zero_write_extaddr(struct spmi_device *dev, |
| unsigned int addr, unsigned char data) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| wdata = (addr&0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_ADDR, &wdata, 1); |
| wdata = (addr>>8)&0xff; |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_H_ADDR, &wdata, 1); |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_ZERO_WRITE, |
| dev->slvid, addr, &data, 1); |
| } |
| |
| int spmi_register_zero_write_set_extaddr(struct spmi_device *dev, |
| unsigned int addr, kal_bool en) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| if (en == KAL_TRUE) { |
| /* assign specific addr */ |
| wdata = (addr&0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_ADDR, &wdata, 1); |
| wdata = (addr>>8)&0xff; |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_H_ADDR, |
| &wdata, 1); |
| } else { |
| /* assign specific addr */ |
| wdata = 0; |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_ADDR, |
| &wdata, 1); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG0_W_H_ADDR, |
| &wdata, 1); |
| } |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return 0; |
| } |
| |
| int spmi_register_read_extaddr(struct spmi_device *dev, unsigned int addr, |
| unsigned char *buf) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| wdata = ((addr >> 5) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_ADDR, &wdata, 1); |
| wdata = ((addr >> 5) & 0xff00); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_H_ADDR, &wdata, 1); |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_READ, |
| dev->slvid, addr, buf, 1); |
| } |
| |
| int spmi_register_write_extaddr(struct spmi_device *dev, unsigned int addr, |
| unsigned char data) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| wdata = ((addr >> 5) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_ADDR, &wdata, 1); |
| wdata = ((addr >> 5) & 0xff00); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_H_ADDR, |
| &wdata, 1); |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_WRITE, |
| dev->slvid, addr, &data, 1); |
| } |
| |
| int spmi_register_rw_set_extaddr(struct spmi_device *dev, unsigned int addr, |
| kal_bool en) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| if (en == KAL_TRUE) { |
| /* assign specific addr */ |
| wdata = ((addr >> 5) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_ADDR, |
| &wdata, 1); |
| wdata = ((addr >> 5) & 0xff00); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_H_ADDR, |
| &wdata, 1); |
| } else { |
| /* assign specific addr */ |
| wdata = 0; |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_ADDR, |
| &wdata, 1); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_REG_RW_H_ADDR, |
| &wdata, 1); |
| } |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return 0; |
| } |
| |
| int spmi_ext_register_read_extaddr(struct spmi_device *dev, unsigned int addr, |
| unsigned char *buf, unsigned short len) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| wdata = ((addr >> 8) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_EXT_REG_RW_ADDR, |
| &wdata, 1); |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READ, |
| dev->slvid, addr, buf, len); |
| } |
| |
| int spmi_ext_register_write_extaddr(struct spmi_device *dev, unsigned int addr, |
| const unsigned char *buf, unsigned short len) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| wdata = ((addr >> 8) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_EXT_REG_RW_ADDR, &wdata, 1); |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITE, |
| dev->slvid, addr, buf, len); |
| } |
| |
| int spmi_ext_register_rw_set_extaddr(struct spmi_device *dev, |
| unsigned int addr, kal_bool en) |
| { |
| unsigned char wdata = 0; |
| |
| spmi_unlock_slave_reg(dev); |
| |
| if ((dev->slvid == SPMI_SLAVE_6) || |
| (dev->slvid == SPMI_SLAVE_7) || |
| (dev->slvid == SPMI_SLAVE_3)) { |
| /* assign specific addr */ |
| if (en == KAL_TRUE) { |
| wdata = ((addr >> 8) & 0xff); |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_EXT_REG_RW_ADDR, |
| &wdata, 1); |
| } else { |
| wdata = 0; |
| spmi_ext_register_writel(dev, |
| MT6315_PMIC_RG_EXTADR_EXT_REG_RW_ADDR, |
| &wdata, 1); |
| } |
| } |
| |
| spmi_lock_slave_reg(dev); |
| |
| return 0; |
| } |
| #endif /* end of SPMI_EXTADDR_SUPPORT */ |
| |
| static int spmi_ctrl_op_st(int mstid, unsigned int grpiden, unsigned int sid, |
| unsigned int cmd) |
| { |
| unsigned int rdata = 0x0; |
| |
| /* gid is 0x800 */ |
| spmi_writel(mstid, SPMI_GRP_ID_EN, grpiden); |
| #if MT63xx_EVB |
| if (grpiden == (1 << SPMI_GROUP_ID)) |
| spmi_writel(mstid, SPMI_OP_ST_CTRL, |
| (cmd << 0x4) | SPMI_GROUP_ID); |
| #else |
| if (grpiden == 0x100) |
| spmi_writel(mstid, SPMI_OP_ST_CTRL, (cmd << 0x4) | 0x8); |
| #endif |
| else |
| spmi_writel(mstid, SPMI_OP_ST_CTRL, (cmd << 0x4) | sid); |
| |
| SPMI_WARN("spmi_ctrl_op_st 0x%x\n", spmi_readl(mstid, SPMI_OP_ST_CTRL)); |
| |
| do |
| { |
| rdata = spmi_readl(mstid, SPMI_OP_ST_STA); |
| SPMI_DBG("spmi_ctrl_op_st 0x%x\n", rdata); |
| |
| if (((rdata >> 0x1) & SPMI_OP_ST_NACK) == SPMI_OP_ST_NACK) { |
| break; |
| } |
| }while((rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY); |
| |
| return 0; |
| } |
| |
| int spmi_command_reset(int mstid, struct spmi_device *dev, unsigned int grpiden) |
| { |
| #if MT63xx_EVB |
| if (grpiden != (1 << SPMI_GROUP_ID)) |
| dev->slvid = grpiden; |
| #else |
| if (grpiden != 0x100) |
| dev->slvid = grpiden; |
| #endif |
| return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_RESET); |
| } |
| int spmi_command_sleep(int mstid, struct spmi_device *dev, unsigned int grpiden) |
| { |
| #if MT63xx_EVB |
| if (grpiden != (1 << SPMI_GROUP_ID)) |
| dev->slvid = grpiden; |
| #else |
| if (grpiden != 0x100) |
| dev->slvid = grpiden; |
| #endif |
| return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_SLEEP); |
| } |
| int spmi_command_wakeup(int mstid, struct spmi_device *dev, unsigned int grpiden) |
| { |
| #if MT63xx_EVB |
| if (grpiden != (1 << SPMI_GROUP_ID)) |
| dev->slvid = grpiden; |
| #else |
| if (grpiden != 0x100) |
| dev->slvid = grpiden; |
| #endif |
| return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_WAKEUP); |
| } |
| int spmi_command_shutdown(int mstid, struct spmi_device *dev, unsigned int grpiden) |
| { |
| #if MT63xx_EVB |
| if (grpiden != (1 << SPMI_GROUP_ID)) |
| dev->slvid = grpiden; |
| #else |
| if (grpiden != 0x100) |
| dev->slvid = grpiden; |
| #endif |
| return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_SHUTDOWN); |
| } |
| |
| int spmi_enable_group_id(int mstid, unsigned int grpiden) |
| { |
| spmi_writel(mstid, SPMI_GRP_ID_EN, grpiden); |
| |
| return 0; |
| } |
| |
| #if SPMI_DEBUG |
| static int spmi_rw_test(struct spmi_device *dev) |
| { |
| unsigned char wdata = 0, rdata = 0; |
| |
| if (dev->mstid == SPMI_MASTER_P_1) { |
| SPMI_INFO("SPMI-P doesn't do %s\n", __func__); |
| return 0; |
| } |
| switch (dev->slvid) { |
| case SPMI_SLAVE_3: |
| case SPMI_SLAVE_6: |
| case SPMI_SLAVE_7: |
| wdata = DEFAULT_VALUE_READ_TEST; |
| spmi_ext_register_writel(dev, MT6315_PMIC_TOP_MDB_RSV1_ADDR, |
| &wdata, 1); |
| spmi_ext_register_readl(dev, MT6315_PMIC_TOP_MDB_RSV1_ADDR, |
| &rdata, 1); |
| if (rdata != DEFAULT_VALUE_READ_TEST) { |
| SPMI_ERR("%s fail_r, slvid:%d rdata = 0x%x.\n", |
| __func__, dev->slvid, rdata); |
| return -EIO; |
| } else |
| SPMI_DBG("%s pass_r, slvid:%d\n", __func__, dev->slvid); |
| |
| wdata = DEFAULT_VALUE_WRITE_TEST; |
| spmi_ext_register_writel(dev, MT6315_PMIC_TOP_MDB_RSV1_H_ADDR, |
| &wdata, 1); |
| |
| spmi_ext_register_readl(dev, MT6315_PMIC_TOP_MDB_RSV1_H_ADDR, |
| &rdata, 1); |
| if (rdata != DEFAULT_VALUE_WRITE_TEST) { |
| SPMI_ERR("%s fail_w, slvid:%d rdata = 0x%x.\n", |
| __func__, dev->slvid, rdata); |
| return -EIO; |
| } else |
| SPMI_DBG("%s pass_w, slvid:%d\n", __func__, dev->slvid); |
| |
| break; |
| case SPMI_SLAVE_9: |
| spmi_read_check(dev); |
| break; |
| case SPMI_SLAVE_8: |
| default: |
| SPMI_ERR("%s not be here, slvid:%d\n", __func__, dev->slvid); |
| break; |
| } |
| return 0; |
| } |
| |
| static int spmi_read_check(struct spmi_device *dev) |
| { |
| unsigned char rdata = 0; |
| |
| spmi_ext_register_readl(dev, dev->hwcid_addr, &rdata, 1); |
| /* mt6362 can only check 0x00[7:4], other mt63xx can align the rule */ |
| if ((rdata & 0xF0) != (dev->hwcid_val & 0xF0)) { |
| SPMI_ERR("%s next, slvid:%d rdata = 0x%x.\n", |
| __func__, dev->slvid, rdata); |
| return -EIO; |
| } else |
| SPMI_DBG("%s done, slvid:%d\n", __func__, dev->slvid); |
| |
| return 0; |
| } |
| |
| static int spmi_drv_ut(struct spmi_device *dev, unsigned int ut) |
| { |
| int ret = 0; |
| |
| switch (ut) { |
| case 1: |
| ret = spmi_rw_test(dev); |
| break; |
| case 2: |
| ret = spmi_read_check(dev); |
| break; |
| case 3: |
| break; |
| default: |
| break; |
| } |
| |
| return ret; |
| } |
| #endif /* end of #if SPMI_DEBUG */ |
| |
| struct spmi_device *get_spmi_device(int mstid, unsigned int slv_type) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < spmi_device_cnt; i++) { |
| if (slv_type == spmi_dev[i].type) { |
| return &spmi_dev[i]; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| int spmi_init(struct pmif *pmif_arb) |
| { |
| int i = 0; |
| #if SPMI_DEBUG |
| int ret = 0; |
| #endif |
| |
| if (pmif_arb == NULL) /* null check */ { |
| SPMI_ERR("arguments err\n"); |
| return -EINVAL; |
| } |
| |
| pmif_arb->spmimst_regs = mt6885_spmi_regs; |
| pmif_spmi_arb_ctrl[pmif_arb->mstid] = pmif_arb; |
| spmi_device_cnt = sizeof(spmi_dev)/sizeof(spmi_dev[0]); |
| |
| if (is_pmif_spmi_init_done(pmif_arb->mstid) != 0) |
| spmi_config_master(pmif_arb->mstid, KAL_TRUE); |
| |
| for (i = 0; i < spmi_device_cnt; i++) { |
| if (pmif_arb->mstid == spmi_dev[i].mstid) { |
| spmi_dev[i].pmif_arb = pmif_spmi_arb_ctrl[pmif_arb->mstid]; |
| if (is_pmif_spmi_init_done(pmif_arb->mstid) != 0) { |
| spmi_config_slave(&spmi_dev[i]); |
| spmi_cali_rd_clock_polarity(&spmi_dev[i], |
| pmif_arb->mstid); |
| } |
| #if SPMI_MONITOR_SUPPORT |
| /* dump 1st time slave debug register when booting */ |
| spmi_dump_slv_record_reg(&spmi_dev[i]); |
| #endif |
| #if SPMI_RCS_SUPPORT |
| if (is_pmif_spmi_init_done() != 0) { |
| /* enable master rcs support */ |
| spmi_writel(pmif_arb->mstid, SPMI_MST_RCS_CTRL, 0x15); |
| spmi_enable_rcs(&spmi_dev[i], pmif_arb->mstid); |
| } |
| #endif |
| |
| #if SPMI_DEBUG |
| /* shouldn't enable at here*/ |
| ret = spmi_drv_ut(&spmi_dev[i], 1); |
| if(ret) { |
| SPMI_ERR("EIO err\n"); |
| return ret; |
| } |
| #endif |
| /*TBD spmi_lock_slave_reg(&spmi_dev[i]); */ |
| } |
| } |
| SPMI_INFO("%s done\n", __func__); |
| |
| return 0; |
| } |
| |
| #endif /* #ifdef SPMI_NO_PMIC */ |