Home | History | Annotate | Download | only in colibri_imx6
      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