1 /* 2 * Copyright (c) 2025, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 9 #include <lib/mmio.h> 10 #include <platform_def.h> 11 12 #include "spmi_common.h" 13 #include "spmi_sw.h" 14 15 /* SPMI Commands */ 16 #define SPMI_CMD_EXT_WRITE 0x00 17 #define SPMI_CMD_EXT_READ 0x20 18 #define SPMI_CMD_EXT_WRITEL 0x30 19 #define SPMI_CMD_EXT_READL 0x38 20 #define SPMI_CMD_WRITE 0x40 21 #define SPMI_CMD_READ 0x60 22 #define SPMI_CMD_ZERO_WRITE 0x80 23 #define SPMI_READ_ADDR_MAX 0x1F 24 25 static struct spmi_device *spmi_dev[SPMI_MAX_SLAVE_ID]; 26 27 int spmi_register_zero_write(struct spmi_device *dev, uint8_t data) 28 { 29 return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_ZERO_WRITE, 30 dev->slvid, 0, &data, 1); 31 } 32 33 int spmi_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf) 34 { 35 /* 5-bit register address */ 36 if (addr > SPMI_READ_ADDR_MAX) 37 return -EINVAL; 38 39 return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_READ, dev->slvid, addr, buf, 1); 40 } 41 42 int spmi_register_write(struct spmi_device *dev, uint8_t addr, uint8_t data) 43 { 44 /* 5-bit register address */ 45 if (addr > SPMI_READ_ADDR_MAX) 46 return -EINVAL; 47 48 return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_WRITE, 49 dev->slvid, addr, &data, 1); 50 } 51 52 int spmi_ext_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf, 53 uint8_t len) 54 { 55 /* 8-bit register address, up to 16 bytes */ 56 if (len == 0 || len > 16) 57 return -EINVAL; 58 59 return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READ, 60 dev->slvid, addr, buf, len); 61 } 62 63 int spmi_ext_register_write(struct spmi_device *dev, uint8_t addr, 64 const uint8_t *buf, uint8_t len) 65 { 66 /* 8-bit register address, up to 16 bytes */ 67 if (len == 0 || len > 16) 68 return -EINVAL; 69 70 return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITE, 71 dev->slvid, addr, buf, len); 72 } 73 74 int spmi_ext_register_readl(struct spmi_device *dev, uint16_t addr, 75 uint8_t *buf, uint8_t len) 76 { 77 /* 8-bit register address, up to 16 bytes */ 78 if (len == 0 || len > 16) 79 return -EINVAL; 80 81 return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL, 82 dev->slvid, addr, buf, len); 83 } 84 85 int spmi_ext_register_writel(struct spmi_device *dev, uint16_t addr, 86 const uint8_t *buf, uint8_t len) 87 { 88 /* 8-bit register address, up to 16 bytes */ 89 if (len == 0 || len > 16) 90 return -EINVAL; 91 92 return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL, 93 dev->slvid, addr, buf, len); 94 } 95 96 int spmi_ext_register_readl_field(struct spmi_device *dev, uint16_t addr, 97 uint8_t *buf, uint16_t mask, uint16_t shift) 98 { 99 int ret; 100 uint8_t rdata = 0; 101 102 ret = dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL, 103 dev->slvid, addr, &rdata, 1); 104 if (!ret) 105 *buf = (rdata >> shift) & mask; 106 107 return ret; 108 } 109 110 int spmi_ext_register_writel_field(struct spmi_device *dev, uint16_t addr, 111 uint8_t data, uint16_t mask, uint16_t shift) 112 { 113 int ret; 114 uint8_t tmp = 0; 115 116 ret = spmi_ext_register_readl(dev, addr, &tmp, 1); 117 if (ret) 118 return ret; 119 120 tmp &= ~(mask << shift); 121 tmp |= (data << shift); 122 return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL, 123 dev->slvid, addr, &tmp, 1); 124 } 125 126 struct spmi_device *get_spmi_device(int mstid, int slvid) 127 { 128 if (slvid >= SPMI_MAX_SLAVE_ID || slvid < 0) { 129 SPMI_ERR("failed to get spmi_device with slave id %d\n", slvid); 130 return NULL; 131 } 132 return spmi_dev[slvid]; 133 } 134 135 int spmi_device_register(struct spmi_device *platform_spmi_dev, unsigned int num_devs) 136 { 137 int i; 138 139 if (!platform_spmi_dev || num_devs == 0) 140 return -EINVAL; 141 142 for (i = 0; i < num_devs; i++) { 143 if (platform_spmi_dev[i].slvid >= SPMI_MAX_SLAVE_ID || 144 platform_spmi_dev[i].slvid < 0) { 145 SPMI_INFO("invalid slave id %d\n", platform_spmi_dev[i].slvid); 146 continue; 147 } 148 if (!spmi_dev[platform_spmi_dev[i].slvid]) 149 spmi_dev[platform_spmi_dev[i].slvid] = &platform_spmi_dev[i]; 150 else { 151 SPMI_INFO("duplicated slave id %d\n", platform_spmi_dev[i].slvid); 152 return -EINVAL; 153 } 154 } 155 return 0; 156 } 157 158 static int spmi_ctrl_op_st(int mstid, unsigned int grpiden, unsigned int sid, 159 unsigned int cmd) 160 { 161 struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); 162 unsigned int rdata = 0x0; 163 uintptr_t spmi_grp_id_en_addr = 164 (uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_GRP_ID_EN]); 165 uintptr_t spmi_op_st_ctrl_addr = 166 (uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_CTRL]); 167 uintptr_t spmi_op_st_sta_addr = 168 (uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_STA]); 169 170 /* gid is 0x800 */ 171 mmio_write_32(spmi_grp_id_en_addr, grpiden); 172 173 if (grpiden == (1 << SPMI_GROUP_ID)) 174 mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | SPMI_GROUP_ID); 175 else 176 mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | sid); 177 178 SPMI_INFO("%s 0x%x\n", __func__, mmio_read_32(spmi_op_st_ctrl_addr)); 179 180 do { 181 rdata = mmio_read_32(spmi_op_st_sta_addr); 182 SPMI_INFO("%s 0x%x\n", __func__, rdata); 183 184 if (((rdata >> 0x1) & SPMI_OP_ST_NACK) == SPMI_OP_ST_NACK) { 185 SPMI_ERR("SPMI_OP_ST_NACK occurs! OP_ST_STA = 0x%x\n", rdata); 186 break; 187 } 188 } while ((rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY); 189 190 return 0; 191 } 192 193 int spmi_command_shutdown(int mstid, struct spmi_device *dev, unsigned int grpiden) 194 { 195 if (grpiden != (1 << SPMI_GROUP_ID)) 196 dev->slvid = grpiden; 197 198 return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_SHUTDOWN); 199 } 200