uboot/drivers/misc/ds4510.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Extreme Engineering Solutions, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 */
   6
   7/*
   8 * Driver for DS4510, a CPU supervisor with integrated EEPROM, SRAM,
   9 * and 4 programmable non-volatile GPIO pins.
  10 */
  11
  12#include <common.h>
  13#include <i2c.h>
  14#include <command.h>
  15#include <ds4510.h>
  16
  17/* Default to an address that hopefully won't corrupt other i2c devices */
  18#ifndef CONFIG_SYS_I2C_DS4510_ADDR
  19#define CONFIG_SYS_I2C_DS4510_ADDR      (~0)
  20#endif
  21
  22enum {
  23        DS4510_CMD_INFO,
  24        DS4510_CMD_DEVICE,
  25        DS4510_CMD_NV,
  26        DS4510_CMD_RSTDELAY,
  27        DS4510_CMD_OUTPUT,
  28        DS4510_CMD_INPUT,
  29        DS4510_CMD_PULLUP,
  30        DS4510_CMD_EEPROM,
  31        DS4510_CMD_SEEPROM,
  32        DS4510_CMD_SRAM,
  33};
  34
  35/*
  36 * Write to DS4510, taking page boundaries into account
  37 */
  38int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count)
  39{
  40        int wrlen;
  41        int i = 0;
  42
  43        do {
  44                wrlen = DS4510_EEPROM_PAGE_SIZE -
  45                        DS4510_EEPROM_PAGE_OFFSET(offset);
  46                if (count < wrlen)
  47                        wrlen = count;
  48                if (i2c_write(chip, offset, 1, &buf[i], wrlen))
  49                        return -1;
  50
  51                /*
  52                 * This delay isn't needed for SRAM writes but shouldn't delay
  53                 * things too much, so do it unconditionally for simplicity
  54                 */
  55                udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
  56                count -= wrlen;
  57                offset += wrlen;
  58                i += wrlen;
  59        } while (count > 0);
  60
  61        return 0;
  62}
  63
  64/*
  65 * General read from DS4510
  66 */
  67int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count)
  68{
  69        return i2c_read(chip, offset, 1, buf, count);
  70}
  71
  72/*
  73 * Write SEE bit in config register.
  74 * nv = 0 - Writes to SEEPROM registers behave like EEPROM
  75 * nv = 1 - Writes to SEEPROM registers behave like SRAM
  76 */
  77int ds4510_see_write(uint8_t chip, uint8_t nv)
  78{
  79        uint8_t data;
  80
  81        if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
  82                return -1;
  83
  84        if (nv) /* Treat SEEPROM bits as EEPROM */
  85                data &= ~DS4510_CFG_SEE;
  86        else    /* Treat SEEPROM bits as SRAM */
  87                data |= DS4510_CFG_SEE;
  88
  89        return ds4510_mem_write(chip, DS4510_CFG, &data, 1);
  90}
  91
  92/*
  93 * Write de-assertion of reset signal delay
  94 */
  95int ds4510_rstdelay_write(uint8_t chip, uint8_t delay)
  96{
  97        uint8_t data;
  98
  99        if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
 100                return -1;
 101
 102        data &= ~DS4510_RSTDELAY_MASK;
 103        data |= delay & DS4510_RSTDELAY_MASK;
 104
 105        return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1);
 106}
 107
 108/*
 109 * Write pullup characteristics of IO pins
 110 */
 111int ds4510_pullup_write(uint8_t chip, uint8_t val)
 112{
 113        val &= DS4510_IO_MASK;
 114
 115        return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1);
 116}
 117
 118/*
 119 * Read pullup characteristics of IO pins
 120 */
 121int ds4510_pullup_read(uint8_t chip)
 122{
 123        uint8_t val;
 124
 125        if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1))
 126                return -1;
 127
 128        return val & DS4510_IO_MASK;
 129}
 130
 131/*
 132 * Write drive level of IO pins
 133 */
 134int ds4510_gpio_write(uint8_t chip, uint8_t val)
 135{
 136        uint8_t data;
 137        int i;
 138
 139        for (i = 0; i < DS4510_NUM_IO; i++) {
 140                if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
 141                        return -1;
 142
 143                if (val & (0x1 << i))
 144                        data |= 0x1;
 145                else
 146                        data &= ~0x1;
 147
 148                if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1))
 149                        return -1;
 150        }
 151
 152        return 0;
 153}
 154
 155/*
 156 * Read drive level of IO pins
 157 */
 158int ds4510_gpio_read(uint8_t chip)
 159{
 160        uint8_t data;
 161        int val = 0;
 162        int i;
 163
 164        for (i = 0; i < DS4510_NUM_IO; i++) {
 165                if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
 166                        return -1;
 167
 168                if (data & 1)
 169                        val |= (1 << i);
 170        }
 171
 172        return val;
 173}
 174
 175/*
 176 * Read physical level of IO pins
 177 */
 178int ds4510_gpio_read_val(uint8_t chip)
 179{
 180        uint8_t val;
 181
 182        if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1))
 183                return -1;
 184
 185        return val & DS4510_IO_MASK;
 186}
 187
 188#ifdef CONFIG_CMD_DS4510
 189#ifdef CONFIG_CMD_DS4510_INFO
 190/*
 191 * Display DS4510 information
 192 */
 193static int ds4510_info(uint8_t chip)
 194{
 195        int i;
 196        int tmp;
 197        uint8_t data;
 198
 199        printf("DS4510 @ 0x%x:\n\n", chip);
 200
 201        if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
 202                return -1;
 203        printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK);
 204
 205        if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
 206                return -1;
 207        printf("config   = 0x%x\n", data);
 208        printf(" /ready  = %d\n", data & DS4510_CFG_READY ? 1 : 0);
 209        printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0);
 210        printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0);
 211        printf(" /see    = %d\n", data & DS4510_CFG_SEE ? 1 : 0);
 212        printf(" swrst   = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0);
 213
 214        printf("gpio pins: 3210\n");
 215        printf("---------------\n");
 216        printf("pullup     ");
 217
 218        tmp = ds4510_pullup_read(chip);
 219        if (tmp == -1)
 220                return tmp;
 221        for (i = DS4510_NUM_IO - 1; i >= 0; i--)
 222                printf("%d", (tmp & (1 << i)) ? 1 : 0);
 223        printf("\n");
 224
 225        printf("driven     ");
 226        tmp = ds4510_gpio_read(chip);
 227        if (tmp == -1)
 228                return -1;
 229        for (i = DS4510_NUM_IO - 1; i >= 0; i--)
 230                printf("%d", (tmp & (1 << i)) ? 1 : 0);
 231        printf("\n");
 232
 233        printf("read       ");
 234        tmp = ds4510_gpio_read_val(chip);
 235        if (tmp == -1)
 236                return -1;
 237        for (i = DS4510_NUM_IO - 1; i >= 0; i--)
 238                printf("%d", (tmp & (1 << i)) ? 1 : 0);
 239        printf("\n");
 240
 241        return 0;
 242}
 243#endif /* CONFIG_CMD_DS4510_INFO */
 244
 245cmd_tbl_t cmd_ds4510[] = {
 246        U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""),
 247        U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""),
 248        U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""),
 249        U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""),
 250        U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""),
 251#ifdef CONFIG_CMD_DS4510_INFO
 252        U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""),
 253#endif
 254#ifdef CONFIG_CMD_DS4510_RST
 255        U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""),
 256#endif
 257#ifdef CONFIG_CMD_DS4510_MEM
 258        U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""),
 259        U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""),
 260        U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""),
 261#endif
 262};
 263
 264int do_ds4510(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 265{
 266        static uint8_t chip = CONFIG_SYS_I2C_DS4510_ADDR;
 267        cmd_tbl_t *c;
 268        ulong ul_arg2 = 0;
 269        ulong ul_arg3 = 0;
 270        int tmp;
 271#ifdef CONFIG_CMD_DS4510_MEM
 272        ulong addr;
 273        ulong off;
 274        ulong cnt;
 275        int end;
 276        int (*rw_func)(uint8_t, int, uint8_t *, int);
 277#endif
 278
 279        c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510));
 280
 281        /* All commands but "device" require 'maxargs' arguments */
 282        if (!c || !((argc == (c->maxargs)) ||
 283                (((int)c->cmd == DS4510_CMD_DEVICE) &&
 284                 (argc == (c->maxargs - 1))))) {
 285                return cmd_usage(cmdtp);
 286        }
 287
 288        /* arg2 used as chip addr and pin number */
 289        if (argc > 2)
 290                ul_arg2 = simple_strtoul(argv[2], NULL, 16);
 291
 292        /* arg3 used as output/pullup value */
 293        if (argc > 3)
 294                ul_arg3 = simple_strtoul(argv[3], NULL, 16);
 295
 296        switch ((int)c->cmd) {
 297        case DS4510_CMD_DEVICE:
 298                if (argc == 3)
 299                        chip = ul_arg2;
 300                printf("Current device address: 0x%x\n", chip);
 301                return 0;
 302        case DS4510_CMD_NV:
 303                return ds4510_see_write(chip, ul_arg2);
 304        case DS4510_CMD_OUTPUT:
 305                tmp = ds4510_gpio_read(chip);
 306                if (tmp == -1)
 307                        return -1;
 308                if (ul_arg3)
 309                        tmp |= (1 << ul_arg2);
 310                else
 311                        tmp &= ~(1 << ul_arg2);
 312                return ds4510_gpio_write(chip, tmp);
 313        case DS4510_CMD_INPUT:
 314                tmp = ds4510_gpio_read_val(chip);
 315                if (tmp == -1)
 316                        return -1;
 317                return (tmp & (1 << ul_arg2)) != 0;
 318        case DS4510_CMD_PULLUP:
 319                tmp = ds4510_pullup_read(chip);
 320                if (tmp == -1)
 321                        return -1;
 322                if (ul_arg3)
 323                        tmp |= (1 << ul_arg2);
 324                else
 325                        tmp &= ~(1 << ul_arg2);
 326                return ds4510_pullup_write(chip, tmp);
 327#ifdef CONFIG_CMD_DS4510_INFO
 328        case DS4510_CMD_INFO:
 329                return ds4510_info(chip);
 330#endif
 331#ifdef CONFIG_CMD_DS4510_RST
 332        case DS4510_CMD_RSTDELAY:
 333                return ds4510_rstdelay_write(chip, ul_arg2);
 334#endif
 335#ifdef CONFIG_CMD_DS4510_MEM
 336        case DS4510_CMD_EEPROM:
 337                end = DS4510_EEPROM + DS4510_EEPROM_SIZE;
 338                off = DS4510_EEPROM;
 339                break;
 340        case DS4510_CMD_SEEPROM:
 341                end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE;
 342                off = DS4510_SEEPROM;
 343                break;
 344        case DS4510_CMD_SRAM:
 345                end = DS4510_SRAM + DS4510_SRAM_SIZE;
 346                off = DS4510_SRAM;
 347                break;
 348#endif
 349        default:
 350                /* We should never get here... */
 351                return 1;
 352        }
 353
 354#ifdef CONFIG_CMD_DS4510_MEM
 355        /* Only eeprom, seeprom, and sram commands should make it here */
 356        if (strcmp(argv[2], "read") == 0)
 357                rw_func = ds4510_mem_read;
 358        else if (strcmp(argv[2], "write") == 0)
 359                rw_func = ds4510_mem_write;
 360        else
 361                return cmd_usage(cmdtp);
 362
 363        addr = simple_strtoul(argv[3], NULL, 16);
 364        off += simple_strtoul(argv[4], NULL, 16);
 365        cnt = simple_strtoul(argv[5], NULL, 16);
 366
 367        if ((off + cnt) > end) {
 368                printf("ERROR: invalid len\n");
 369                return -1;
 370        }
 371
 372        return rw_func(chip, off, (uint8_t *)addr, cnt);
 373#endif
 374}
 375
 376U_BOOT_CMD(
 377        ds4510, 6,      1,      do_ds4510,
 378        "ds4510 eeprom/seeprom/sram/gpio access",
 379        "device [dev]\n"
 380        "       - show or set current device address\n"
 381#ifdef CONFIG_CMD_DS4510_INFO
 382        "ds4510 info\n"
 383        "       - display ds4510 info\n"
 384#endif
 385        "ds4510 output pin 0|1\n"
 386        "       - set pin low or high-Z\n"
 387        "ds4510 input pin\n"
 388        "       - read value of pin\n"
 389        "ds4510 pullup pin 0|1\n"
 390        "       - disable/enable pullup on specified pin\n"
 391        "ds4510 nv 0|1\n"
 392        "       - make gpio and seeprom writes volatile/non-volatile"
 393#ifdef CONFIG_CMD_DS4510_RST
 394        "\n"
 395        "ds4510 rstdelay 0-3\n"
 396        "       - set reset output delay"
 397#endif
 398#ifdef CONFIG_CMD_DS4510_MEM
 399        "\n"
 400        "ds4510 eeprom read addr off cnt\n"
 401        "ds4510 eeprom write addr off cnt\n"
 402        "       - read/write 'cnt' bytes at EEPROM offset 'off'\n"
 403        "ds4510 seeprom read addr off cnt\n"
 404        "ds4510 seeprom write addr off cnt\n"
 405        "       - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n"
 406        "ds4510 sram read addr off cnt\n"
 407        "ds4510 sram write addr off cnt\n"
 408        "       - read/write 'cnt' bytes at SRAM offset 'off'"
 409#endif
 410);
 411#endif /* CONFIG_CMD_DS4510 */
 412