1 /* 2 * Copyright (C) 2014-2016, Toradex AG 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 /* 8 * Helpers for Freescale PMIC PF0100 9 */ 10 11 #include <common.h> 12 #include <i2c.h> 13 #include <asm/arch/imx-regs.h> 14 #include <asm/arch/iomux.h> 15 #include <asm/arch/mx6-pins.h> 16 #include <asm/gpio.h> 17 #include <asm/mach-imx/iomux-v3.h> 18 19 #include "pf0100_otp.inc" 20 #include "pf0100.h" 21 22 /* define for PMIC register dump */ 23 /*#define DEBUG */ 24 25 /* use Apalis GPIO1 to switch on VPGM, ON: 1 */ 26 static iomux_v3_cfg_t const pmic_prog_pads[] = { 27 MX6_PAD_NANDF_D4__GPIO2_IO04 | MUX_PAD_CTRL(NO_PAD_CTRL), 28 # define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 4) 29 }; 30 31 unsigned pmic_init(void) 32 { 33 unsigned programmed = 0; 34 uchar bus = 1; 35 uchar devid, revid, val; 36 37 puts("PMIC: "); 38 if (!((0 == i2c_set_bus_num(bus)) && 39 (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 40 puts("i2c bus failed\n"); 41 return 0; 42 } 43 /* get device ident */ 44 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_DEVICEID, 1, &devid, 1) < 0) { 45 puts("i2c pmic devid read failed\n"); 46 return 0; 47 } 48 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_REVID, 1, &revid, 1) < 0) { 49 puts("i2c pmic revid read failed\n"); 50 return 0; 51 } 52 printf("device id: 0x%.2x, revision id: 0x%.2x\n", devid, revid); 53 54 #ifdef DEBUG 55 { 56 unsigned i, j; 57 58 for (i = 0; i < 16; i++) 59 printf("\t%x", i); 60 for (j = 0; j < 0x80; ) { 61 printf("\n%2x", j); 62 for (i = 0; i < 16; i++) { 63 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 64 printf("\t%2x", val); 65 } 66 j += 0x10; 67 } 68 printf("\nEXT Page 1"); 69 70 val = PFUZE100_PAGE_REGISTER_PAGE1; 71 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 72 &val, 1)) { 73 puts("i2c write failed\n"); 74 return 0; 75 } 76 77 for (j = 0x80; j < 0x100; ) { 78 printf("\n%2x", j); 79 for (i = 0; i < 16; i++) { 80 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 81 printf("\t%2x", val); 82 } 83 j += 0x10; 84 } 85 printf("\nEXT Page 2"); 86 87 val = PFUZE100_PAGE_REGISTER_PAGE2; 88 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 89 &val, 1)) { 90 puts("i2c write failed\n"); 91 return 0; 92 } 93 94 for (j = 0x80; j < 0x100; ) { 95 printf("\n%2x", j); 96 for (i = 0; i < 16; i++) { 97 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 98 printf("\t%2x", val); 99 } 100 j += 0x10; 101 } 102 printf("\n"); 103 } 104 #endif 105 /* get device programmed state */ 106 val = PFUZE100_PAGE_REGISTER_PAGE1; 107 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, &val, 1)) { 108 puts("i2c write failed\n"); 109 return 0; 110 } 111 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR1, 1, &val, 1) < 0) { 112 puts("i2c fuse_por read failed\n"); 113 return 0; 114 } 115 if (val & PFUZE100_FUSE_POR_M) 116 programmed++; 117 118 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR2, 1, &val, 1) < 0) { 119 puts("i2c fuse_por read failed\n"); 120 return programmed; 121 } 122 if (val & PFUZE100_FUSE_POR_M) 123 programmed++; 124 125 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR3, 1, &val, 1) < 0) { 126 puts("i2c fuse_por read failed\n"); 127 return programmed; 128 } 129 if (val & PFUZE100_FUSE_POR_M) 130 programmed++; 131 132 switch (programmed) { 133 case 0: 134 printf("PMIC: not programmed\n"); 135 break; 136 case 3: 137 printf("PMIC: programmed\n"); 138 break; 139 default: 140 printf("PMIC: undefined programming state\n"); 141 break; 142 } 143 144 /* The following is needed during production */ 145 if (programmed != 3) { 146 /* set VGEN1 to 1.2V */ 147 val = PFUZE100_VGEN1_VAL; 148 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_VGEN1CTL, 1, 149 &val, 1)) { 150 puts("i2c write failed\n"); 151 return programmed; 152 } 153 154 /* set SWBST to 5.0V */ 155 val = PFUZE100_SWBST_VAL; 156 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_SWBSTCTL, 1, 157 &val, 1)) { 158 puts("i2c write failed\n"); 159 } 160 } 161 return programmed; 162 } 163 164 int pf0100_prog(void) 165 { 166 unsigned char bus = 1; 167 unsigned char val; 168 unsigned int i; 169 170 if (pmic_init() == 3) { 171 puts("PMIC already programmed, exiting\n"); 172 return CMD_RET_FAILURE; 173 } 174 /* set up gpio to manipulate vprog, initially off */ 175 imx_iomux_v3_setup_multiple_pads(pmic_prog_pads, 176 ARRAY_SIZE(pmic_prog_pads)); 177 gpio_direction_output(PMIC_PROG_VOLTAGE, 0); 178 179 if (!((0 == i2c_set_bus_num(bus)) && 180 (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 181 puts("i2c bus failed\n"); 182 return CMD_RET_FAILURE; 183 } 184 185 for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) { 186 switch (pmic_otp_prog[i].cmd) { 187 case pmic_i2c: 188 val = (unsigned char) (pmic_otp_prog[i].value & 0xff); 189 if (i2c_write(PFUZE100_I2C_ADDR, pmic_otp_prog[i].reg, 190 1, &val, 1)) { 191 printf("i2c write failed, reg 0x%2x, value 0x%2x\n", 192 pmic_otp_prog[i].reg, val); 193 return CMD_RET_FAILURE; 194 } 195 break; 196 case pmic_delay: 197 udelay(pmic_otp_prog[i].value * 1000); 198 break; 199 case pmic_vpgm: 200 gpio_direction_output(PMIC_PROG_VOLTAGE, 201 pmic_otp_prog[i].value); 202 break; 203 case pmic_pwr: 204 /* TODO */ 205 break; 206 } 207 } 208 return CMD_RET_SUCCESS; 209 } 210 211 int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc, 212 char * const argv[]) 213 { 214 int ret; 215 puts("Programming PMIC OTP..."); 216 ret = pf0100_prog(); 217 if (ret == CMD_RET_SUCCESS) 218 puts("done.\n"); 219 else 220 puts("failed.\n"); 221 return ret; 222 } 223 224 U_BOOT_CMD( 225 pf0100_otp_prog, 1, 0, do_pf0100_prog, 226 "Program the OTP fuses on the PMIC PF0100", 227 "" 228 ); 229