1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2014-2016, Toradex AG 4 */ 5 6 /* 7 * Helpers for Freescale PMIC PF0100 8 */ 9 10 #include <common.h> 11 #include <i2c.h> 12 #include <asm/arch/imx-regs.h> 13 #include <asm/arch/iomux.h> 14 #include <asm/arch/mx6-pins.h> 15 #include <asm/gpio.h> 16 #include <asm/mach-imx/iomux-v3.h> 17 18 #include "pf0100_otp.inc" 19 #include "pf0100.h" 20 21 /* define for PMIC register dump */ 22 /*#define DEBUG */ 23 24 /* use GPIO: EXT_IO1 to switch on VPGM, ON: 1 */ 25 static __maybe_unused iomux_v3_cfg_t const pmic_prog_pads[] = { 26 MX6_PAD_NANDF_D3__GPIO2_IO03 | MUX_PAD_CTRL(NO_PAD_CTRL), 27 # define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 3) 28 }; 29 30 unsigned pmic_init(void) 31 { 32 unsigned programmed = 0; 33 uchar bus = 1; 34 uchar devid, revid, val; 35 36 puts("PMIC: "); 37 if (!((0 == i2c_set_bus_num(bus)) && 38 (0 == i2c_probe(PFUZE100_I2C_ADDR)))) { 39 puts("i2c bus failed\n"); 40 return 0; 41 } 42 /* get device ident */ 43 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_DEVICEID, 1, &devid, 1) < 0) { 44 puts("i2c pmic devid read failed\n"); 45 return 0; 46 } 47 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_REVID, 1, &revid, 1) < 0) { 48 puts("i2c pmic revid read failed\n"); 49 return 0; 50 } 51 printf("device id: 0x%.2x, revision id: 0x%.2x\n", devid, revid); 52 53 #ifdef DEBUG 54 { 55 unsigned i, j; 56 57 for (i = 0; i < 16; i++) 58 printf("\t%x", i); 59 for (j = 0; j < 0x80; ) { 60 printf("\n%2x", j); 61 for (i = 0; i < 16; i++) { 62 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 63 printf("\t%2x", val); 64 } 65 j += 0x10; 66 } 67 printf("\nEXT Page 1"); 68 69 val = PFUZE100_PAGE_REGISTER_PAGE1; 70 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 71 &val, 1)) { 72 puts("i2c write failed\n"); 73 return 0; 74 } 75 76 for (j = 0x80; j < 0x100; ) { 77 printf("\n%2x", j); 78 for (i = 0; i < 16; i++) { 79 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 80 printf("\t%2x", val); 81 } 82 j += 0x10; 83 } 84 printf("\nEXT Page 2"); 85 86 val = PFUZE100_PAGE_REGISTER_PAGE2; 87 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, 88 &val, 1)) { 89 puts("i2c write failed\n"); 90 return 0; 91 } 92 93 for (j = 0x80; j < 0x100; ) { 94 printf("\n%2x", j); 95 for (i = 0; i < 16; i++) { 96 i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1); 97 printf("\t%2x", val); 98 } 99 j += 0x10; 100 } 101 printf("\n"); 102 } 103 #endif 104 /* get device programmed state */ 105 val = PFUZE100_PAGE_REGISTER_PAGE1; 106 if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, &val, 1)) { 107 puts("i2c write failed\n"); 108 return 0; 109 } 110 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR1, 1, &val, 1) < 0) { 111 puts("i2c fuse_por read failed\n"); 112 return 0; 113 } 114 if (val & PFUZE100_FUSE_POR_M) 115 programmed++; 116 117 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR2, 1, &val, 1) < 0) { 118 puts("i2c fuse_por read failed\n"); 119 return programmed; 120 } 121 if (val & PFUZE100_FUSE_POR_M) 122 programmed++; 123 124 if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR3, 1, &val, 1) < 0) { 125 puts("i2c fuse_por read failed\n"); 126 return programmed; 127 } 128 if (val & PFUZE100_FUSE_POR_M) 129 programmed++; 130 131 switch (programmed) { 132 case 0: 133 printf("PMIC: not programmed\n"); 134 break; 135 case 3: 136 printf("PMIC: programmed\n"); 137 break; 138 default: 139 printf("PMIC: undefined programming state\n"); 140 break; 141 } 142 143 return programmed; 144 } 145 146 #ifndef CONFIG_SPL_BUILD 147 static 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 static 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 #endif 213