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