mb/system76/cml-u/dt: Make use of chipset devicetree
[coreboot.git] / src / soc / mediatek / mt8195 / mt6360.c
blobb613acf34032316b83b47ed7fdb6fac9af042afe
1 /* SPDX-License-Identifier: GPL-2.0-only OR MIT */
3 #include <console/console.h>
4 #include <device/i2c_simple.h>
5 #include <soc/mt6360.h>
6 #include <stdbool.h>
8 static struct mt6360_i2c_data i2c_data[] = {
9 [MT6360_INDEX_LDO] = {
10 .addr = MT6360_LDO_I2C_ADDR,
12 [MT6360_INDEX_PMIC] = {
13 .addr = MT6360_PMIC_I2C_ADDR,
17 static const uint32_t mt6360_ldo1_vsel_table[0x10] = {
18 [0x4] = 1800000,
19 [0x5] = 2000000,
20 [0x6] = 2100000,
21 [0x7] = 2500000,
22 [0x8] = 2700000,
23 [0x9] = 2800000,
24 [0xA] = 2900000,
25 [0xB] = 3000000,
26 [0xC] = 3100000,
27 [0xD] = 3300000,
30 static const uint32_t mt6360_ldo3_vsel_table[0x10] = {
31 [0x4] = 1800000,
32 [0xA] = 2900000,
33 [0xB] = 3000000,
34 [0xD] = 3300000,
37 static const uint32_t mt6360_ldo5_vsel_table[0x10] = {
38 [0x2] = 2900000,
39 [0x3] = 3000000,
40 [0x5] = 3300000,
43 static const struct mt6360_data regulator_data[MT6360_REGULATOR_COUNT] = {
44 [MT6360_LDO3] = MT6360_DATA(0x05, 0x40, 0x09, 0xff, mt6360_ldo3_vsel_table),
45 [MT6360_LDO5] = MT6360_DATA(0x0b, 0x40, 0x0f, 0xff, mt6360_ldo5_vsel_table),
46 [MT6360_LDO6] = MT6360_DATA(0x37, 0x40, 0x3b, 0xff, mt6360_ldo3_vsel_table),
47 [MT6360_LDO7] = MT6360_DATA(0x31, 0x40, 0x35, 0xff, mt6360_ldo5_vsel_table),
48 [MT6360_BUCK1] = MT6360_DATA(0x17, 0x40, 0x10, 0xff, mt6360_ldo1_vsel_table),
49 [MT6360_BUCK2] = MT6360_DATA(0x27, 0x40, 0x20, 0xff, mt6360_ldo1_vsel_table),
50 [MT6360_LDO1] = MT6360_DATA(0x17, 0x40, 0x1b, 0xff, mt6360_ldo1_vsel_table),
51 [MT6360_LDO2] = MT6360_DATA(0x11, 0x40, 0x15, 0xff, mt6360_ldo1_vsel_table),
54 #define CRC8_TABLE_SIZE 256
55 static u8 crc8_table[MT6360_INDEX_COUNT][CRC8_TABLE_SIZE];
57 static u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes)
59 u8 crc = 0;
61 while (nbytes-- > 0)
62 crc = table[(crc ^ *pdata++) & 0xff];
64 return crc;
67 static void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
69 int i, j;
70 const u8 msbit = 0x80;
71 u8 t = msbit;
73 table[0] = 0;
75 for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) {
76 t = (t << 1) ^ (t & msbit ? polynomial : 0);
77 for (j = 0; j < i; j++)
78 table[i + j] = table[j] ^ t;
82 static int mt6360_i2c_write_byte(u8 index, u8 reg, u8 data)
84 u8 chunk[5] = { 0 };
85 struct mt6360_i2c_data *i2c = &i2c_data[index];
87 if ((reg & 0xc0) != 0) {
88 printk(BIOS_ERR, "%s: not support reg [%#x]\n", __func__, reg);
89 return -1;
93 * chunk[0], dev address
94 * chunk[1], reg address
95 * chunk[2], data to write
96 * chunk[3], crc of chunk[0 ~ 2]
97 * chunk[4], blank
99 chunk[0] = (i2c->addr & 0x7f) << 1;
100 chunk[1] = (reg & 0x3f);
101 chunk[2] = data;
102 chunk[3] = crc8(crc8_table[index], chunk, 3);
104 return i2c_write_raw(i2c->bus, i2c->addr, &chunk[1], 4);
107 static int mt6360_i2c_read_byte(u8 index, u8 reg, u8 *data)
109 u8 chunk[4] = { 0 };
110 u8 buf[2];
111 int ret;
112 u8 crc;
113 struct mt6360_i2c_data *i2c = &i2c_data[index];
115 ret = i2c_read_bytes(i2c->bus, i2c->addr, reg & 0x3f, buf, 2);
117 if (ret)
118 return ret;
120 * chunk[0], dev address
121 * chunk[1], reg address
122 * chunk[2], received data
123 * chunk[3], received crc of chunk[0 ~ 2]
125 chunk[0] = ((i2c->addr & 0x7f) << 1) + 1;
126 chunk[1] = (reg & 0x3f);
127 chunk[2] = buf[0];
128 chunk[3] = buf[1];
129 crc = crc8(crc8_table[index], chunk, 3);
131 if (chunk[3] != crc) {
132 printk(BIOS_ERR, "%s: incorrect CRC: expected %#x, got %#x",
133 __func__, crc, chunk[3]);
134 return -1;
137 *data = chunk[2];
139 return 0;
142 static int mt6360_read_interface(u8 index, u8 reg, u8 *data, u8 mask, u8 shift)
144 int ret;
145 u8 val = 0;
147 ret = mt6360_i2c_read_byte(index, reg, &val);
148 if (ret < 0) {
149 printk(BIOS_ERR, "%s: fail, reg = %#x, ret = %d\n",
150 __func__, reg, ret);
151 return ret;
153 val &= (mask << shift);
154 *data = (val >> shift);
155 return 0;
158 static int mt6360_config_interface(u8 index, u8 reg, u8 data, u8 mask, u8 shift)
160 int ret;
161 u8 val = 0;
163 ret = mt6360_i2c_read_byte(index, reg, &val);
164 if (ret < 0) {
165 printk(BIOS_ERR, "%s: fail, reg = %#x, ret = %d\n",
166 __func__, reg, ret);
167 return ret;
169 val &= ~(mask << shift);
170 val |= (data << shift);
172 return mt6360_i2c_write_byte(index, reg, val);
175 static bool is_valid_ldo(enum mt6360_regulator_id id)
177 if (id != MT6360_LDO1 && id != MT6360_LDO2 &&
178 id != MT6360_LDO3 && id != MT6360_LDO5) {
179 printk(BIOS_ERR, "%s: LDO %d is not supported\n", __func__, id);
180 return false;
183 return true;
186 static bool is_valid_pmic(enum mt6360_regulator_id id)
188 if (id != MT6360_LDO6 && id != MT6360_LDO7 &&
189 id != MT6360_BUCK1 && id != MT6360_BUCK2) {
190 printk(BIOS_ERR, "%s: PMIC %d is not supported\n", __func__, id);
191 return false;
194 return true;
197 static void mt6360_ldo_enable(enum mt6360_regulator_id id, uint8_t enable)
199 u8 val;
200 const struct mt6360_data *data;
202 if (!is_valid_ldo(id))
203 return;
205 data = &regulator_data[id];
207 if (mt6360_read_interface(MT6360_INDEX_LDO, data->enable_reg, &val, 0xff, 0) < 0)
208 return;
210 if (enable)
211 val |= data->enable_mask;
212 else
213 val &= ~(data->enable_mask);
215 mt6360_config_interface(MT6360_INDEX_LDO, data->enable_reg, val, 0xff, 0);
218 static uint8_t mt6360_ldo_is_enabled(enum mt6360_regulator_id id)
220 u8 val;
221 const struct mt6360_data *data;
223 if (!is_valid_ldo(id))
224 return 0;
226 data = &regulator_data[id];
228 if (mt6360_read_interface(MT6360_INDEX_LDO, data->enable_reg, &val, 0xff, 0) < 0)
229 return 0;
231 return (val & data->enable_mask) ? 1 : 0;
234 static void mt6360_ldo_set_voltage(enum mt6360_regulator_id id, u32 voltage_uv)
236 u8 val = 0;
237 u32 voltage_uv_temp = 0;
238 int i;
240 const struct mt6360_data *data;
242 if (!is_valid_ldo(id))
243 return;
245 data = &regulator_data[id];
247 for (i = 0; i < data->vsel_table_len; i++) {
248 u32 uv = data->vsel_table[i];
250 if (uv == 0)
251 continue;
252 if (uv > voltage_uv)
253 break;
255 val = i << 4;
256 voltage_uv_temp = voltage_uv - uv;
259 if (val == 0) {
260 printk(BIOS_ERR, "%s: LDO %d, set %d uV not supported\n",
261 __func__, id, voltage_uv);
262 return;
265 voltage_uv_temp /= 10000;
266 voltage_uv_temp = MIN(voltage_uv_temp, 0xa);
267 val |= (u8)voltage_uv_temp;
269 mt6360_config_interface(MT6360_INDEX_LDO, data->vsel_reg, val, 0xff, 0);
272 static u32 mt6360_ldo_get_voltage(enum mt6360_regulator_id id)
274 u8 val;
275 u32 voltage_uv;
277 const struct mt6360_data *data;
279 if (!is_valid_ldo(id))
280 return 0;
282 data = &regulator_data[id];
284 if (mt6360_read_interface(MT6360_INDEX_LDO, data->vsel_reg, &val, 0xff, 0) < 0)
285 return 0;
287 voltage_uv = data->vsel_table[(val & 0xf0) >> 4];
288 if (voltage_uv == 0) {
289 printk(BIOS_ERR, "%s: LDO %d read fail, reg = %#x\n", __func__, id, val);
290 return 0;
293 val = MIN(val & 0x0f, 0x0a);
294 voltage_uv += val * 10000;
296 return voltage_uv;
299 static void mt6360_pmic_enable(enum mt6360_regulator_id id, uint8_t enable)
301 u8 val;
302 const struct mt6360_data *data;
304 if (!is_valid_pmic(id))
305 return;
307 data = &regulator_data[id];
309 if (mt6360_read_interface(MT6360_INDEX_PMIC, data->enable_reg, &val, 0xff, 0) < 0)
310 return;
312 if (enable)
313 val |= data->enable_mask;
314 else
315 val &= ~(data->enable_mask);
317 mt6360_config_interface(MT6360_INDEX_PMIC, data->enable_reg, val, 0xff, 0);
320 static uint8_t mt6360_pmic_is_enabled(enum mt6360_regulator_id id)
322 u8 val;
323 const struct mt6360_data *data;
325 if (!is_valid_pmic(id))
326 return 0;
328 data = &regulator_data[id];
330 if (mt6360_read_interface(MT6360_INDEX_PMIC, data->enable_reg, &val, 0xff, 0) < 0)
331 return 0;
333 return (val & data->enable_mask) ? 1 : 0;
336 static void mt6360_pmic_set_voltage(enum mt6360_regulator_id id, u32 voltage_uv)
338 u8 val = 0;
340 const struct mt6360_data *data;
342 if (!is_valid_pmic(id))
343 return;
345 data = &regulator_data[id];
347 if (id == MT6360_BUCK1 || id == MT6360_BUCK2) {
348 val = (voltage_uv - 300000) / 5000;
349 } else if (id == MT6360_LDO6 || id == MT6360_LDO7) {
350 val = (((voltage_uv - 500000) / 100000) << 4);
351 val += (((voltage_uv - 500000) % 100000) / 10000);
354 mt6360_config_interface(MT6360_INDEX_PMIC, data->vsel_reg, val, 0xff, 0);
357 static u32 mt6360_pmic_get_voltage(enum mt6360_regulator_id id)
359 u8 val;
360 u32 voltage_uv = 0;
362 const struct mt6360_data *data;
364 if (!is_valid_pmic(id))
365 return 0;
367 data = &regulator_data[id];
369 if (mt6360_read_interface(MT6360_INDEX_PMIC, data->vsel_reg, &val, 0xff, 0) < 0)
370 return 0;
372 if (id == MT6360_BUCK1 || id == MT6360_BUCK2) {
373 voltage_uv = 300000 + val * 5000;
374 } else if (id == MT6360_LDO6 || id == MT6360_LDO7) {
375 voltage_uv = 500000 + 100000 * (val >> 4);
376 voltage_uv += MIN(val & 0xf, 0xa) * 10000;
379 return voltage_uv;
382 void mt6360_init(uint8_t bus)
384 u8 delay01, delay02, delay03, delay04;
386 crc8_populate_msb(crc8_table[MT6360_INDEX_LDO], 0x7);
387 crc8_populate_msb(crc8_table[MT6360_INDEX_PMIC], 0x7);
389 i2c_data[MT6360_INDEX_LDO].bus = bus;
390 i2c_data[MT6360_INDEX_PMIC].bus = bus;
392 mt6360_config_interface(MT6360_INDEX_PMIC, 0x07, 0x04, 0xff, 0);
393 mt6360_config_interface(MT6360_INDEX_PMIC, 0x08, 0x00, 0xff, 0);
394 mt6360_config_interface(MT6360_INDEX_PMIC, 0x09, 0x02, 0xff, 0);
395 mt6360_config_interface(MT6360_INDEX_PMIC, 0x0a, 0x00, 0xff, 0);
397 mt6360_read_interface(MT6360_INDEX_PMIC, 0x07, &delay01, 0xff, 0);
398 mt6360_read_interface(MT6360_INDEX_PMIC, 0x08, &delay02, 0xff, 0);
399 mt6360_read_interface(MT6360_INDEX_PMIC, 0x09, &delay03, 0xff, 0);
400 mt6360_read_interface(MT6360_INDEX_PMIC, 0x0a, &delay04, 0xff, 0);
401 printk(BIOS_DEBUG,
402 "%s: power off sequence delay: %#x, %#x, %#x, %#x\n",
403 __func__, delay01, delay02, delay03, delay04);
406 void mt6360_enable(enum mt6360_regulator_id id, uint8_t enable)
408 if (is_valid_ldo(id))
409 mt6360_ldo_enable(id, enable);
410 else if (is_valid_pmic(id))
411 mt6360_pmic_enable(id, enable);
414 uint8_t mt6360_is_enabled(enum mt6360_regulator_id id)
416 if (is_valid_ldo(id))
417 return mt6360_ldo_is_enabled(id);
418 else if (is_valid_pmic(id))
419 return mt6360_pmic_is_enabled(id);
420 else
421 return 0;
424 void mt6360_set_voltage(enum mt6360_regulator_id id, u32 voltage_uv)
426 if (is_valid_ldo(id))
427 mt6360_ldo_set_voltage(id, voltage_uv);
428 else if (is_valid_pmic(id))
429 mt6360_pmic_set_voltage(id, voltage_uv);
432 u32 mt6360_get_voltage(enum mt6360_regulator_id id)
434 if (is_valid_ldo(id))
435 return mt6360_ldo_get_voltage(id);
436 else if (is_valid_pmic(id))
437 return mt6360_pmic_get_voltage(id);
438 else
439 return 0;