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 GPIO: EXT_IO1 to switch on VPGM, ON: 1 */ 26 static iomux_v3_cfg_t const pmic_prog_pads[] = { 27 MX6_PAD_NANDF_D3__GPIO2_IO03 | MUX_PAD_CTRL(NO_PAD_CTRL), 28 # define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 3) 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 return programmed; 145 } 146 147 int pf0100_prog(void) 148 { 149 unsigned char bus = 1; 150 unsigned char val; 151 unsigned int i; 152 153 if (pmic_init() == 3) { 154 puts("PMIC already programmed, exiting\n"); 155 return CMD_RET_FAILURE; 156 } 157 /* set up gpio to manipulate vprog, initially off */ 158 imx_iomux_v3_setup_multiple_pads(pmic_prog_pads, 159 ARRAY_SIZE(pmic_prog_pads)); 160 gpio_direction_output(PMIC_PROG_VOLTAGE, 0); 161 162 if (!((0 == i2c_set_bus_num(bus)) && 163 (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 164 puts("i2c bus failed\n"); 165 return CMD_RET_FAILURE; 166 } 167 168 for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) { 169 switch (pmic_otp_prog[i].cmd) { 170 case pmic_i2c: 171 val = (unsigned char) (pmic_otp_prog[i].value & 0xff); 172 if (i2c_write(PFUZE100_I2C_ADDR, pmic_otp_prog[i].reg, 173 1, &val, 1)) { 174 printf("i2c write failed, reg 0x%2x, value 0x%2x\n", 175 pmic_otp_prog[i].reg, val); 176 return CMD_RET_FAILURE; 177 } 178 break; 179 case pmic_delay: 180 udelay(pmic_otp_prog[i].value * 1000); 181 break; 182 case pmic_vpgm: 183 gpio_direction_output(PMIC_PROG_VOLTAGE, 184 pmic_otp_prog[i].value); 185 break; 186 case pmic_pwr: 187 /* TODO */ 188 break; 189 } 190 } 191 return CMD_RET_SUCCESS; 192 } 193 194 int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc, 195 char * const argv[]) 196 { 197 int ret; 198 puts("Programming PMIC OTP..."); 199 ret = pf0100_prog(); 200 if (ret == CMD_RET_SUCCESS) 201 puts("done.\n"); 202 else 203 puts("failed.\n"); 204 return ret; 205 } 206 207 U_BOOT_CMD( 208 pf0100_otp_prog, 1, 0, do_pf0100_prog, 209 "Program the OTP fuses on the PMIC PF0100", 210 "" 211 ); 212