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
spmi_register_zero_write(struct spmi_device * dev,uint8_t data)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
spmi_register_read(struct spmi_device * dev,uint8_t addr,uint8_t * buf)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
spmi_register_write(struct spmi_device * dev,uint8_t addr,uint8_t data)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
spmi_ext_register_read(struct spmi_device * dev,uint8_t addr,uint8_t * buf,uint8_t len)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
spmi_ext_register_write(struct spmi_device * dev,uint8_t addr,const uint8_t * buf,uint8_t len)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
spmi_ext_register_readl(struct spmi_device * dev,uint16_t addr,uint8_t * buf,uint8_t len)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
spmi_ext_register_writel(struct spmi_device * dev,uint16_t addr,const uint8_t * buf,uint8_t len)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
spmi_ext_register_readl_field(struct spmi_device * dev,uint16_t addr,uint8_t * buf,uint16_t mask,uint16_t shift)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
spmi_ext_register_writel_field(struct spmi_device * dev,uint16_t addr,uint8_t data,uint16_t mask,uint16_t shift)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
get_spmi_device(int mstid,int slvid)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
spmi_device_register(struct spmi_device * platform_spmi_dev,unsigned int num_devs)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
spmi_ctrl_op_st(int mstid,unsigned int grpiden,unsigned int sid,unsigned int cmd)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
spmi_command_shutdown(int mstid,struct spmi_device * dev,unsigned int grpiden)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