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 * const 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                return cmd_usage(cmdtp);
 298        }
 299
 300        /* arg2 used as chip addr and pin number */
 301        if (argc > 2)
 302                ul_arg2 = simple_strtoul(argv[2], NULL, 16);
 303
 304        /* arg3 used as output/pullup value */
 305        if (argc > 3)
 306                ul_arg3 = simple_strtoul(argv[3], NULL, 16);
 307
 308        switch ((int)c->cmd) {
 309        case DS4510_CMD_DEVICE:
 310                if (argc == 3)
 311                        chip = ul_arg2;
 312                printf("Current device address: 0x%x\n", chip);
 313                return 0;
 314        case DS4510_CMD_NV:
 315                return ds4510_see_write(chip, ul_arg2);
 316        case DS4510_CMD_OUTPUT:
 317                tmp = ds4510_gpio_read(chip);
 318                if (tmp == -1)
 319                        return -1;
 320                if (ul_arg3)
 321                        tmp |= (1 << ul_arg2);
 322                else
 323                        tmp &= ~(1 << ul_arg2);
 324                return ds4510_gpio_write(chip, tmp);
 325        case DS4510_CMD_INPUT:
 326                tmp = ds4510_gpio_read_val(chip);
 327                if (tmp == -1)
 328                        return -1;
 329                return (tmp & (1 << ul_arg2)) != 0;
 330        case DS4510_CMD_PULLUP:
 331                tmp = ds4510_pullup_read(chip);
 332                if (tmp == -1)
 333                        return -1;
 334                if (ul_arg3)
 335                        tmp |= (1 << ul_arg2);
 336                else
 337                        tmp &= ~(1 << ul_arg2);
 338                return ds4510_pullup_write(chip, tmp);
 339#ifdef CONFIG_CMD_DS4510_INFO
 340        case DS4510_CMD_INFO:
 341                return ds4510_info(chip);
 342#endif
 343#ifdef CONFIG_CMD_DS4510_RST
 344        case DS4510_CMD_RSTDELAY:
 345                return ds4510_rstdelay_write(chip, ul_arg2);
 346#endif
 347#ifdef CONFIG_CMD_DS4510_MEM
 348        case DS4510_CMD_EEPROM:
 349                end = DS4510_EEPROM + DS4510_EEPROM_SIZE;
 350                off = DS4510_EEPROM;
 351                break;
 352        case DS4510_CMD_SEEPROM:
 353                end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE;
 354                off = DS4510_SEEPROM;
 355                break;
 356        case DS4510_CMD_SRAM:
 357                end = DS4510_SRAM + DS4510_SRAM_SIZE;
 358                off = DS4510_SRAM;
 359                break;
 360#endif
 361        default:
 362                /* We should never get here... */
 363                return 1;
 364        }
 365
 366#ifdef CONFIG_CMD_DS4510_MEM
 367        /* Only eeprom, seeprom, and sram commands should make it here */
 368        if (strcmp(argv[2], "read") == 0)
 369                rw_func = ds4510_mem_read;
 370        else if (strcmp(argv[2], "write") == 0)
 371                rw_func = ds4510_mem_write;
 372        else
 373                return cmd_usage(cmdtp);
 374
 375        addr = simple_strtoul(argv[3], NULL, 16);
 376        off += simple_strtoul(argv[4], NULL, 16);
 377        cnt = simple_strtoul(argv[5], NULL, 16);
 378
 379        if ((off + cnt) > end) {
 380                printf("ERROR: invalid len\n");
 381                return -1;
 382        }
 383
 384        return rw_func(chip, off, (uint8_t *)addr, cnt);
 385#endif
 386}
 387
 388U_BOOT_CMD(
 389        ds4510, 6,      1,      do_ds4510,
 390        "ds4510 eeprom/seeprom/sram/gpio access",
 391        "device [dev]\n"
 392        "       - show or set current device address\n"
 393#ifdef CONFIG_CMD_DS4510_INFO
 394        "ds4510 info\n"
 395        "       - display ds4510 info\n"
 396#endif
 397        "ds4510 output pin 0|1\n"
 398        "       - set pin low or high-Z\n"
 399        "ds4510 input pin\n"
 400        "       - read value of pin\n"
 401        "ds4510 pullup pin 0|1\n"
 402        "       - disable/enable pullup on specified pin\n"
 403        "ds4510 nv 0|1\n"
 404        "       - make gpio and seeprom writes volatile/non-volatile"
 405#ifdef CONFIG_CMD_DS4510_RST
 406        "\n"
 407        "ds4510 rstdelay 0-3\n"
 408        "       - set reset output delay"
 409#endif
 410#ifdef CONFIG_CMD_DS4510_MEM
 411        "\n"
 412        "ds4510 eeprom read addr off cnt\n"
 413        "ds4510 eeprom write addr off cnt\n"
 414        "       - read/write 'cnt' bytes at EEPROM offset 'off'\n"
 415        "ds4510 seeprom read addr off cnt\n"
 416        "ds4510 seeprom write addr off cnt\n"
 417        "       - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n"
 418        "ds4510 sram read addr off cnt\n"
 419        "ds4510 sram write addr off cnt\n"
 420        "       - read/write 'cnt' bytes at SRAM offset 'off'"
 421#endif
 422);
 423#endif /* CONFIG_CMD_DS4510 */
 424