1592f4aedSMax Krummenacher /* 2592f4aedSMax Krummenacher * Copyright (C) 2014-2016, Toradex AG 3592f4aedSMax Krummenacher * 4592f4aedSMax Krummenacher * SPDX-License-Identifier: GPL-2.0+ 5592f4aedSMax Krummenacher */ 6592f4aedSMax Krummenacher 7592f4aedSMax Krummenacher /* 8592f4aedSMax Krummenacher * Helpers for Freescale PMIC PF0100 9592f4aedSMax Krummenacher */ 10592f4aedSMax Krummenacher 11592f4aedSMax Krummenacher #include <common.h> 12592f4aedSMax Krummenacher #include <i2c.h> 13592f4aedSMax Krummenacher #include <asm/arch/imx-regs.h> 14592f4aedSMax Krummenacher #include <asm/arch/iomux.h> 15592f4aedSMax Krummenacher #include <asm/arch/mx6-pins.h> 16592f4aedSMax Krummenacher #include <asm/gpio.h> 17*552a848eSStefano Babic #include <asm/mach-imx/iomux-v3.h> 18592f4aedSMax Krummenacher 19592f4aedSMax Krummenacher #include "pf0100_otp.inc" 20592f4aedSMax Krummenacher #include "pf0100.h" 21592f4aedSMax Krummenacher 22592f4aedSMax Krummenacher /* define for PMIC register dump */ 23592f4aedSMax Krummenacher /*#define DEBUG */ 24592f4aedSMax Krummenacher 25592f4aedSMax Krummenacher /* use Apalis GPIO1 to switch on VPGM, ON: 1 */ 26592f4aedSMax Krummenacher static iomux_v3_cfg_t const pmic_prog_pads[] = { 27592f4aedSMax Krummenacher MX6_PAD_NANDF_D4__GPIO2_IO04 | MUX_PAD_CTRL(NO_PAD_CTRL), 28592f4aedSMax Krummenacher # define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 4) 29592f4aedSMax Krummenacher }; 30592f4aedSMax Krummenacher 31592f4aedSMax Krummenacher unsigned pmic_init(void) 32592f4aedSMax Krummenacher { 33592f4aedSMax Krummenacher unsigned programmed = 0; 34592f4aedSMax Krummenacher uchar bus = 1; 35592f4aedSMax Krummenacher uchar devid, revid, val; 36592f4aedSMax Krummenacher 37592f4aedSMax Krummenacher puts("PMIC: "); 38592f4aedSMax Krummenacher if (!((0 == i2c_set_bus_num(bus)) && 39592f4aedSMax Krummenacher (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 40592f4aedSMax Krummenacher puts("i2c bus failed\n"); 41592f4aedSMax Krummenacher return 0; 42592f4aedSMax Krummenacher } 43592f4aedSMax Krummenacher /* get device ident */ 44592f4aedSMax Krummenacher if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_DEVICEID, 1, &devid, 1) < 0) { 45592f4aedSMax Krummenacher puts("i2c pmic devid read failed\n"); 46592f4aedSMax Krummenacher return 0; 47592f4aedSMax Krummenacher } 48592f4aedSMax Krummenacher if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_REVID, 1, &revid, 1) < 0) { 49592f4aedSMax Krummenacher puts("i2c pmic revid read failed\n"); 50592f4aedSMax Krummenacher return 0; 51592f4aedSMax Krummenacher } 52592f4aedSMax Krummenacher printf("device id: 0x%.2x, revision id: 0x%.2x\n", devid, revid); 53592f4aedSMax Krummenacher 54592f4aedSMax Krummenacher #ifdef DEBUG 55592f4aedSMax Krummenacher { 56592f4aedSMax Krummenacher unsigned i, j; 57592f4aedSMax Krummenacher 58592f4aedSMax Krummenacher for (i = 0; i < 16; i++) 59592f4aedSMax Krummenacher printf("\t%x", i); 60592f4aedSMax Krummenacher for (j = 0; j < 0x80; ) { 61592f4aedSMax Krummenacher printf("\n%2x", j); 62592f4aedSMax Krummenacher for (i = 0; i < 16; i++) { 63592f4aedSMax Krummenacher i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 64592f4aedSMax Krummenacher printf("\t%2x", val); 65592f4aedSMax Krummenacher } 66592f4aedSMax Krummenacher j += 0x10; 67592f4aedSMax Krummenacher } 68592f4aedSMax Krummenacher printf("\nEXT Page 1"); 69592f4aedSMax Krummenacher 70592f4aedSMax Krummenacher val = PFUZE100_PAGE_REGISTER_PAGE1; 71592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 72592f4aedSMax Krummenacher &val, 1)) { 73592f4aedSMax Krummenacher puts("i2c write failed\n"); 74592f4aedSMax Krummenacher return 0; 75592f4aedSMax Krummenacher } 76592f4aedSMax Krummenacher 77592f4aedSMax Krummenacher for (j = 0x80; j < 0x100; ) { 78592f4aedSMax Krummenacher printf("\n%2x", j); 79592f4aedSMax Krummenacher for (i = 0; i < 16; i++) { 80592f4aedSMax Krummenacher i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 81592f4aedSMax Krummenacher printf("\t%2x", val); 82592f4aedSMax Krummenacher } 83592f4aedSMax Krummenacher j += 0x10; 84592f4aedSMax Krummenacher } 85592f4aedSMax Krummenacher printf("\nEXT Page 2"); 86592f4aedSMax Krummenacher 87592f4aedSMax Krummenacher val = PFUZE100_PAGE_REGISTER_PAGE2; 88592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 89592f4aedSMax Krummenacher &val, 1)) { 90592f4aedSMax Krummenacher puts("i2c write failed\n"); 91592f4aedSMax Krummenacher return 0; 92592f4aedSMax Krummenacher } 93592f4aedSMax Krummenacher 94592f4aedSMax Krummenacher for (j = 0x80; j < 0x100; ) { 95592f4aedSMax Krummenacher printf("\n%2x", j); 96592f4aedSMax Krummenacher for (i = 0; i < 16; i++) { 97592f4aedSMax Krummenacher i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 98592f4aedSMax Krummenacher printf("\t%2x", val); 99592f4aedSMax Krummenacher } 100592f4aedSMax Krummenacher j += 0x10; 101592f4aedSMax Krummenacher } 102592f4aedSMax Krummenacher printf("\n"); 103592f4aedSMax Krummenacher } 104592f4aedSMax Krummenacher #endif 105592f4aedSMax Krummenacher /* get device programmed state */ 106592f4aedSMax Krummenacher val = PFUZE100_PAGE_REGISTER_PAGE1; 107592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, &val, 1)) { 108592f4aedSMax Krummenacher puts("i2c write failed\n"); 109592f4aedSMax Krummenacher return 0; 110592f4aedSMax Krummenacher } 111592f4aedSMax Krummenacher if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR1, 1, &val, 1) < 0) { 112592f4aedSMax Krummenacher puts("i2c fuse_por read failed\n"); 113592f4aedSMax Krummenacher return 0; 114592f4aedSMax Krummenacher } 115592f4aedSMax Krummenacher if (val & PFUZE100_FUSE_POR_M) 116592f4aedSMax Krummenacher programmed++; 117592f4aedSMax Krummenacher 118592f4aedSMax Krummenacher if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR2, 1, &val, 1) < 0) { 119592f4aedSMax Krummenacher puts("i2c fuse_por read failed\n"); 120592f4aedSMax Krummenacher return programmed; 121592f4aedSMax Krummenacher } 122592f4aedSMax Krummenacher if (val & PFUZE100_FUSE_POR_M) 123592f4aedSMax Krummenacher programmed++; 124592f4aedSMax Krummenacher 125592f4aedSMax Krummenacher if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR3, 1, &val, 1) < 0) { 126592f4aedSMax Krummenacher puts("i2c fuse_por read failed\n"); 127592f4aedSMax Krummenacher return programmed; 128592f4aedSMax Krummenacher } 129592f4aedSMax Krummenacher if (val & PFUZE100_FUSE_POR_M) 130592f4aedSMax Krummenacher programmed++; 131592f4aedSMax Krummenacher 132592f4aedSMax Krummenacher switch (programmed) { 133592f4aedSMax Krummenacher case 0: 134592f4aedSMax Krummenacher printf("PMIC: not programmed\n"); 135592f4aedSMax Krummenacher break; 136592f4aedSMax Krummenacher case 3: 137592f4aedSMax Krummenacher printf("PMIC: programmed\n"); 138592f4aedSMax Krummenacher break; 139592f4aedSMax Krummenacher default: 140592f4aedSMax Krummenacher printf("PMIC: undefined programming state\n"); 141592f4aedSMax Krummenacher break; 142592f4aedSMax Krummenacher } 143592f4aedSMax Krummenacher 144592f4aedSMax Krummenacher /* The following is needed during production */ 145592f4aedSMax Krummenacher if (programmed != 3) { 146592f4aedSMax Krummenacher /* set VGEN1 to 1.2V */ 147592f4aedSMax Krummenacher val = PFUZE100_VGEN1_VAL; 148592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_VGEN1CTL, 1, 149592f4aedSMax Krummenacher &val, 1)) { 150592f4aedSMax Krummenacher puts("i2c write failed\n"); 151592f4aedSMax Krummenacher return programmed; 152592f4aedSMax Krummenacher } 153592f4aedSMax Krummenacher 154592f4aedSMax Krummenacher /* set SWBST to 5.0V */ 155592f4aedSMax Krummenacher val = PFUZE100_SWBST_VAL; 156592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_SWBSTCTL, 1, 157592f4aedSMax Krummenacher &val, 1)) { 158592f4aedSMax Krummenacher puts("i2c write failed\n"); 159592f4aedSMax Krummenacher } 160592f4aedSMax Krummenacher } 161592f4aedSMax Krummenacher return programmed; 162592f4aedSMax Krummenacher } 163592f4aedSMax Krummenacher 164592f4aedSMax Krummenacher int pf0100_prog(void) 165592f4aedSMax Krummenacher { 166592f4aedSMax Krummenacher unsigned char bus = 1; 167592f4aedSMax Krummenacher unsigned char val; 168592f4aedSMax Krummenacher unsigned int i; 169592f4aedSMax Krummenacher 170592f4aedSMax Krummenacher if (pmic_init() == 3) { 171592f4aedSMax Krummenacher puts("PMIC already programmed, exiting\n"); 172592f4aedSMax Krummenacher return CMD_RET_FAILURE; 173592f4aedSMax Krummenacher } 174592f4aedSMax Krummenacher /* set up gpio to manipulate vprog, initially off */ 175592f4aedSMax Krummenacher imx_iomux_v3_setup_multiple_pads(pmic_prog_pads, 176592f4aedSMax Krummenacher ARRAY_SIZE(pmic_prog_pads)); 177592f4aedSMax Krummenacher gpio_direction_output(PMIC_PROG_VOLTAGE, 0); 178592f4aedSMax Krummenacher 179592f4aedSMax Krummenacher if (!((0 == i2c_set_bus_num(bus)) && 180592f4aedSMax Krummenacher (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 181592f4aedSMax Krummenacher puts("i2c bus failed\n"); 182592f4aedSMax Krummenacher return CMD_RET_FAILURE; 183592f4aedSMax Krummenacher } 184592f4aedSMax Krummenacher 185592f4aedSMax Krummenacher for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) { 186592f4aedSMax Krummenacher switch (pmic_otp_prog[i].cmd) { 187592f4aedSMax Krummenacher case pmic_i2c: 188592f4aedSMax Krummenacher val = (unsigned char) (pmic_otp_prog[i].value & 0xff); 189592f4aedSMax Krummenacher if (i2c_write(PFUZE100_I2C_ADDR, pmic_otp_prog[i].reg, 190592f4aedSMax Krummenacher 1, &val, 1)) { 191592f4aedSMax Krummenacher printf("i2c write failed, reg 0x%2x, value 0x%2x\n", 192592f4aedSMax Krummenacher pmic_otp_prog[i].reg, val); 193592f4aedSMax Krummenacher return CMD_RET_FAILURE; 194592f4aedSMax Krummenacher } 195592f4aedSMax Krummenacher break; 196592f4aedSMax Krummenacher case pmic_delay: 197592f4aedSMax Krummenacher udelay(pmic_otp_prog[i].value * 1000); 198592f4aedSMax Krummenacher break; 199592f4aedSMax Krummenacher case pmic_vpgm: 200592f4aedSMax Krummenacher gpio_direction_output(PMIC_PROG_VOLTAGE, 201592f4aedSMax Krummenacher pmic_otp_prog[i].value); 202592f4aedSMax Krummenacher break; 203592f4aedSMax Krummenacher case pmic_pwr: 204592f4aedSMax Krummenacher /* TODO */ 205592f4aedSMax Krummenacher break; 206592f4aedSMax Krummenacher } 207592f4aedSMax Krummenacher } 208592f4aedSMax Krummenacher return CMD_RET_SUCCESS; 209592f4aedSMax Krummenacher } 210592f4aedSMax Krummenacher 211592f4aedSMax Krummenacher int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc, 212592f4aedSMax Krummenacher char * const argv[]) 213592f4aedSMax Krummenacher { 214592f4aedSMax Krummenacher int ret; 215592f4aedSMax Krummenacher puts("Programming PMIC OTP..."); 216592f4aedSMax Krummenacher ret = pf0100_prog(); 217592f4aedSMax Krummenacher if (ret == CMD_RET_SUCCESS) 218592f4aedSMax Krummenacher puts("done.\n"); 219592f4aedSMax Krummenacher else 220592f4aedSMax Krummenacher puts("failed.\n"); 221592f4aedSMax Krummenacher return ret; 222592f4aedSMax Krummenacher } 223592f4aedSMax Krummenacher 224592f4aedSMax Krummenacher U_BOOT_CMD( 225592f4aedSMax Krummenacher pf0100_otp_prog, 1, 0, do_pf0100_prog, 226592f4aedSMax Krummenacher "Program the OTP fuses on the PMIC PF0100", 227592f4aedSMax Krummenacher "" 228592f4aedSMax Krummenacher ); 229