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