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