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