uboot/board/toradex/apalis_imx6/pf0100.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2014-2019, Toradex AG
   4 */
   5
   6/*
   7 * Helpers for Freescale PMIC PF0100
   8*/
   9
  10#include <common.h>
  11#include <command.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#include <linux/delay.h>
  19
  20#include "pf0100_otp.inc"
  21#include "pf0100.h"
  22
  23/* define for PMIC register dump */
  24/*#define DEBUG */
  25
  26#define WARNBAR "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
  27
  28/* use Apalis GPIO1 to switch on VPGM, ON: 1 */
  29static __maybe_unused iomux_v3_cfg_t const pmic_prog_pads[] = {
  30        MX6_PAD_NANDF_D4__GPIO2_IO04 | MUX_PAD_CTRL(NO_PAD_CTRL),
  31#       define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 4)
  32};
  33
  34unsigned pmic_init(void)
  35{
  36        int rc;
  37        struct udevice *dev = NULL;
  38        unsigned programmed = 0;
  39        uchar bus = 1;
  40        uchar devid, revid, val;
  41
  42        puts("PMIC:  ");
  43        rc = i2c_get_chip_for_busnum(bus, PFUZE100_I2C_ADDR, 1, &dev);
  44        if (rc) {
  45                printf("failed to get device for PMIC at address 0x%x\n",
  46                       PFUZE100_I2C_ADDR);
  47                return 0;
  48        }
  49
  50        /* check for errors in PMIC fuses */
  51        if (dm_i2c_read(dev, PFUZE100_INTSTAT3, &val, 1) < 0) {
  52                puts("i2c pmic INTSTAT3 register read failed\n");
  53                return 0;
  54        }
  55        if (val & PFUZE100_BIT_OTP_ECCI) {
  56                puts("\n" WARNBAR);
  57                puts("WARNING: ecc errors found in pmic fuse banks\n");
  58                puts(WARNBAR);
  59        }
  60        if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE1, &val, 1) < 0) {
  61                puts("i2c pmic ECC_SE1 register read failed\n");
  62                return 0;
  63        }
  64        if (val & PFUZE100_BITS_ECC_SE1) {
  65                puts(WARNBAR);
  66                puts("WARNING: ecc has made bit corrections in banks 1 to 5\n");
  67                puts(WARNBAR);
  68        }
  69        if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE2, &val, 1) < 0) {
  70                puts("i2c pmic ECC_SE2 register read failed\n");
  71                return 0;
  72        }
  73        if (val & PFUZE100_BITS_ECC_SE2) {
  74                puts(WARNBAR);
  75                puts("WARNING: ecc has made bit corrections in banks 6 to 10\n"
  76                    );
  77                puts(WARNBAR);
  78        }
  79        if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE1, &val, 1) < 0) {
  80                puts("i2c pmic ECC_DE register read failed\n");
  81                return 0;
  82        }
  83        if (val & PFUZE100_BITS_ECC_DE1) {
  84                puts(WARNBAR);
  85                puts("ERROR: banks 1 to 5 have uncorrectable bits\n");
  86                puts(WARNBAR);
  87        }
  88        if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE2, &val, 1) < 0) {
  89                puts("i2c pmic ECC_DE register read failed\n");
  90                return 0;
  91        }
  92        if (val & PFUZE100_BITS_ECC_DE2) {
  93                puts(WARNBAR);
  94                puts("ERROR: banks 6 to 10 have uncorrectable bits\n");
  95                puts(WARNBAR);
  96        }
  97
  98        /* get device ident */
  99        if (dm_i2c_read(dev, PFUZE100_DEVICEID, &devid, 1) < 0) {
 100                puts("i2c pmic devid read failed\n");
 101                return 0;
 102        }
 103        if (dm_i2c_read(dev, PFUZE100_REVID, &revid, 1) < 0) {
 104                puts("i2c pmic revid read failed\n");
 105                return 0;
 106        }
 107        printf("device id: 0x%.2x, revision id: 0x%.2x, ", devid, revid);
 108
 109        /* get device programmed state */
 110        val = PFUZE100_PAGE_REGISTER_PAGE1;
 111        if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 112                puts("i2c write failed\n");
 113                return 0;
 114        }
 115        if (dm_i2c_read(dev, PFUZE100_FUSE_POR1, &val, 1) < 0) {
 116                puts("i2c fuse_por read failed\n");
 117                return 0;
 118        }
 119        if (val & PFUZE100_FUSE_POR_M)
 120                programmed++;
 121
 122        if (dm_i2c_read(dev, PFUZE100_FUSE_POR2, &val, 1) < 0) {
 123                puts("i2c fuse_por read failed\n");
 124                return programmed;
 125        }
 126        if (val & PFUZE100_FUSE_POR_M)
 127                programmed++;
 128
 129        if (dm_i2c_read(dev, PFUZE100_FUSE_POR3, &val, 1) < 0) {
 130                puts("i2c fuse_por read failed\n");
 131                return programmed;
 132        }
 133        if (val & PFUZE100_FUSE_POR_M)
 134                programmed++;
 135
 136        switch (programmed) {
 137        case 0:
 138                puts("not programmed\n");
 139                break;
 140        case 3:
 141                puts("programmed\n");
 142                break;
 143        default:
 144                puts("undefined programming state\n");
 145                break;
 146        }
 147
 148        /* The following is needed during production */
 149        if (programmed != 3) {
 150                /* set VGEN1 to 1.2V */
 151                val = PFUZE100_VGEN1_VAL;
 152                if (dm_i2c_write(dev, PFUZE100_VGEN1CTL, &val, 1)) {
 153                        puts("i2c write failed\n");
 154                        return programmed;
 155                }
 156
 157                /* set SWBST to 5.0V */
 158                val = PFUZE100_SWBST_VAL;
 159                if (dm_i2c_write(dev, PFUZE100_SWBSTCTL, &val, 1))
 160                        puts("i2c write failed\n");
 161        }
 162
 163#ifdef DEBUG
 164        {
 165                unsigned int i, j;
 166
 167                for (i = 0; i < 16; i++)
 168                        printf("\t%x", i);
 169                for (j = 0; j < 0x80; ) {
 170                        printf("\n%2x", j);
 171                        for (i = 0; i < 16; i++) {
 172                                dm_i2c_read(dev, j + i, &val, 1);
 173                                printf("\t%2x", val);
 174                        }
 175                        j += 0x10;
 176                }
 177                printf("\nEXT Page 1");
 178
 179                val = PFUZE100_PAGE_REGISTER_PAGE1;
 180                if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 181                        puts("i2c write failed\n");
 182                        return 0;
 183                }
 184
 185                for (j = 0x80; j < 0x100; ) {
 186                        printf("\n%2x", j);
 187                        for (i = 0; i < 16; i++) {
 188                                dm_i2c_read(dev, j + i, &val, 1);
 189                                printf("\t%2x", val);
 190                        }
 191                        j += 0x10;
 192                }
 193                printf("\nEXT Page 2");
 194
 195                val = PFUZE100_PAGE_REGISTER_PAGE2;
 196                if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 197                        puts("i2c write failed\n");
 198                        return 0;
 199                }
 200
 201                for (j = 0x80; j < 0x100; ) {
 202                        printf("\n%2x", j);
 203                        for (i = 0; i < 16; i++) {
 204                                dm_i2c_read(dev, j + i, &val, 1);
 205                                printf("\t%2x", val);
 206                        }
 207                        j += 0x10;
 208                }
 209                printf("\n");
 210        }
 211#endif /* DEBUG */
 212
 213        return programmed;
 214}
 215
 216#ifndef CONFIG_SPL_BUILD
 217static int pf0100_prog(void)
 218{
 219        int rc;
 220        struct udevice *dev = NULL;
 221        unsigned char bus = 1;
 222        unsigned char val;
 223        unsigned int i;
 224
 225        if (pmic_init() == 3) {
 226                puts("PMIC already programmed, exiting\n");
 227                return CMD_RET_FAILURE;
 228        }
 229        /* set up gpio to manipulate vprog, initially off */
 230        imx_iomux_v3_setup_multiple_pads(pmic_prog_pads,
 231                                         ARRAY_SIZE(pmic_prog_pads));
 232        gpio_direction_output(PMIC_PROG_VOLTAGE, 0);
 233
 234        rc = i2c_get_chip_for_busnum(bus, PFUZE100_I2C_ADDR, 1, &dev);
 235        if (rc) {
 236                printf("failed to get device for PMIC at address 0x%x\n",
 237                       PFUZE100_I2C_ADDR);
 238                return CMD_RET_FAILURE;
 239        }
 240
 241        for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) {
 242                switch (pmic_otp_prog[i].cmd) {
 243                case pmic_i2c:
 244                        val = (unsigned char) (pmic_otp_prog[i].value & 0xff);
 245                        if (dm_i2c_write(dev, pmic_otp_prog[i].reg, &val, 1)) {
 246                                printf("i2c write failed, reg 0x%2x, value 0x%2x\n",
 247                                       pmic_otp_prog[i].reg, val);
 248                                return CMD_RET_FAILURE;
 249                        }
 250                        break;
 251                case pmic_delay:
 252                        udelay(pmic_otp_prog[i].value * 1000);
 253                        break;
 254                case pmic_vpgm:
 255                        gpio_direction_output(PMIC_PROG_VOLTAGE,
 256                                              pmic_otp_prog[i].value);
 257                        break;
 258                case pmic_pwr:
 259                        /* TODO */
 260                        break;
 261                }
 262        }
 263        return CMD_RET_SUCCESS;
 264}
 265
 266static int do_pf0100_prog(struct cmd_tbl *cmdtp, int flag, int argc,
 267                          char *const argv[])
 268{
 269        int ret;
 270        puts("Programming PMIC OTP...");
 271        ret = pf0100_prog();
 272        if (ret == CMD_RET_SUCCESS)
 273                puts("done.\n");
 274        else
 275                puts("failed.\n");
 276        return ret;
 277}
 278
 279U_BOOT_CMD(
 280        pf0100_otp_prog, 1, 0, do_pf0100_prog,
 281        "Program the OTP fuses on the PMIC PF0100",
 282        ""
 283);
 284#endif /* CONFIG_SPL_BUILD */
 285