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>
8 static struct mt6360_i2c_data i2c_data
[] = {
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] = {
30 static const uint32_t mt6360_ldo3_vsel_table
[0x10] = {
37 static const uint32_t mt6360_ldo5_vsel_table
[0x10] = {
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
)
62 crc
= table
[(crc
^ *pdata
++) & 0xff];
67 static void crc8_populate_msb(u8 table
[CRC8_TABLE_SIZE
], u8 polynomial
)
70 const u8 msbit
= 0x80;
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
)
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
);
93 * chunk[0], dev address
94 * chunk[1], reg address
95 * chunk[2], data to write
96 * chunk[3], crc of chunk[0 ~ 2]
99 chunk
[0] = (i2c
->addr
& 0x7f) << 1;
100 chunk
[1] = (reg
& 0x3f);
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
)
113 struct mt6360_i2c_data
*i2c
= &i2c_data
[index
];
115 ret
= i2c_read_bytes(i2c
->bus
, i2c
->addr
, reg
& 0x3f, buf
, 2);
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);
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]);
142 static int mt6360_read_interface(u8 index
, u8 reg
, u8
*data
, u8 mask
, u8 shift
)
147 ret
= mt6360_i2c_read_byte(index
, reg
, &val
);
149 printk(BIOS_ERR
, "%s: fail, reg = %#x, ret = %d\n",
153 val
&= (mask
<< shift
);
154 *data
= (val
>> shift
);
158 static int mt6360_config_interface(u8 index
, u8 reg
, u8 data
, u8 mask
, u8 shift
)
163 ret
= mt6360_i2c_read_byte(index
, reg
, &val
);
165 printk(BIOS_ERR
, "%s: fail, reg = %#x, ret = %d\n",
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
);
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
);
197 static void mt6360_ldo_enable(enum mt6360_regulator_id id
, uint8_t enable
)
200 const struct mt6360_data
*data
;
202 if (!is_valid_ldo(id
))
205 data
= ®ulator_data
[id
];
207 if (mt6360_read_interface(MT6360_INDEX_LDO
, data
->enable_reg
, &val
, 0xff, 0) < 0)
211 val
|= data
->enable_mask
;
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
)
221 const struct mt6360_data
*data
;
223 if (!is_valid_ldo(id
))
226 data
= ®ulator_data
[id
];
228 if (mt6360_read_interface(MT6360_INDEX_LDO
, data
->enable_reg
, &val
, 0xff, 0) < 0)
231 return (val
& data
->enable_mask
) ? 1 : 0;
234 static void mt6360_ldo_set_voltage(enum mt6360_regulator_id id
, u32 voltage_uv
)
237 u32 voltage_uv_temp
= 0;
240 const struct mt6360_data
*data
;
242 if (!is_valid_ldo(id
))
245 data
= ®ulator_data
[id
];
247 for (i
= 0; i
< data
->vsel_table_len
; i
++) {
248 u32 uv
= data
->vsel_table
[i
];
256 voltage_uv_temp
= voltage_uv
- uv
;
260 printk(BIOS_ERR
, "%s: LDO %d, set %d uV not supported\n",
261 __func__
, id
, voltage_uv
);
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
)
277 const struct mt6360_data
*data
;
279 if (!is_valid_ldo(id
))
282 data
= ®ulator_data
[id
];
284 if (mt6360_read_interface(MT6360_INDEX_LDO
, data
->vsel_reg
, &val
, 0xff, 0) < 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
);
293 val
= MIN(val
& 0x0f, 0x0a);
294 voltage_uv
+= val
* 10000;
299 static void mt6360_pmic_enable(enum mt6360_regulator_id id
, uint8_t enable
)
302 const struct mt6360_data
*data
;
304 if (!is_valid_pmic(id
))
307 data
= ®ulator_data
[id
];
309 if (mt6360_read_interface(MT6360_INDEX_PMIC
, data
->enable_reg
, &val
, 0xff, 0) < 0)
313 val
|= data
->enable_mask
;
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
)
323 const struct mt6360_data
*data
;
325 if (!is_valid_pmic(id
))
328 data
= ®ulator_data
[id
];
330 if (mt6360_read_interface(MT6360_INDEX_PMIC
, data
->enable_reg
, &val
, 0xff, 0) < 0)
333 return (val
& data
->enable_mask
) ? 1 : 0;
336 static void mt6360_pmic_set_voltage(enum mt6360_regulator_id id
, u32 voltage_uv
)
340 const struct mt6360_data
*data
;
342 if (!is_valid_pmic(id
))
345 data
= ®ulator_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
)
362 const struct mt6360_data
*data
;
364 if (!is_valid_pmic(id
))
367 data
= ®ulator_data
[id
];
369 if (mt6360_read_interface(MT6360_INDEX_PMIC
, data
->vsel_reg
, &val
, 0xff, 0) < 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;
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);
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
);
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
);