uboot/drivers/i2c/i2c-uniphier.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <linux/types.h>
   9#include <linux/io.h>
  10#include <linux/sizes.h>
  11#include <asm/errno.h>
  12#include <dm/device.h>
  13#include <dm/root.h>
  14#include <i2c.h>
  15#include <fdtdec.h>
  16#include <mapmem.h>
  17
  18struct uniphier_i2c_regs {
  19        u32 dtrm;                       /* data transmission */
  20#define I2C_DTRM_STA    (1 << 10)
  21#define I2C_DTRM_STO    (1 << 9)
  22#define I2C_DTRM_NACK   (1 << 8)
  23#define I2C_DTRM_RD     (1 << 0)
  24        u32 drec;                       /* data reception */
  25#define I2C_DREC_STS    (1 << 12)
  26#define I2C_DREC_LRB    (1 << 11)
  27#define I2C_DREC_LAB    (1 << 9)
  28        u32 myad;                       /* slave address */
  29        u32 clk;                        /* clock frequency control */
  30        u32 brst;                       /* bus reset */
  31#define I2C_BRST_FOEN   (1 << 1)
  32#define I2C_BRST_BRST   (1 << 0)
  33        u32 hold;                       /* hold time control */
  34        u32 bsts;                       /* bus status monitor */
  35        u32 noise;                      /* noise filter control */
  36        u32 setup;                      /* setup time control */
  37};
  38
  39#define IOBUS_FREQ      100000000
  40
  41struct uniphier_i2c_dev {
  42        struct uniphier_i2c_regs __iomem *regs; /* register base */
  43        unsigned long input_clk;        /* master clock (Hz) */
  44        unsigned long wait_us;          /* wait for every byte transfer (us) */
  45};
  46
  47static int uniphier_i2c_probe(struct udevice *dev)
  48{
  49        fdt_addr_t addr;
  50        struct uniphier_i2c_dev *priv = dev_get_priv(dev);
  51
  52        addr = dev_get_addr(dev);
  53        if (addr == FDT_ADDR_T_NONE)
  54                return -EINVAL;
  55
  56        priv->regs = map_sysmem(addr, SZ_64);
  57        if (!priv->regs)
  58                return -ENOMEM;
  59
  60        priv->input_clk = IOBUS_FREQ;
  61
  62        /* deassert reset */
  63        writel(0x3, &priv->regs->brst);
  64
  65        return 0;
  66}
  67
  68static int uniphier_i2c_remove(struct udevice *dev)
  69{
  70        struct uniphier_i2c_dev *priv = dev_get_priv(dev);
  71
  72        unmap_sysmem(priv->regs);
  73
  74        return 0;
  75}
  76
  77static int send_and_recv_byte(struct uniphier_i2c_dev *dev, u32 dtrm)
  78{
  79        writel(dtrm, &dev->regs->dtrm);
  80
  81        /*
  82         * This controller only provides interruption to inform the completion
  83         * of each byte transfer.  (No status register to poll it.)
  84         * Unfortunately, U-Boot does not have a good support of interrupt.
  85         * Wait for a while.
  86         */
  87        udelay(dev->wait_us);
  88
  89        return readl(&dev->regs->drec);
  90}
  91
  92static int send_byte(struct uniphier_i2c_dev *dev, u32 dtrm, bool *stop)
  93{
  94        int ret = 0;
  95        u32 drec;
  96
  97        drec = send_and_recv_byte(dev, dtrm);
  98
  99        if (drec & I2C_DREC_LAB) {
 100                debug("uniphier_i2c: bus arbitration failed\n");
 101                *stop = false;
 102                ret = -EREMOTEIO;
 103        }
 104        if (drec & I2C_DREC_LRB) {
 105                debug("uniphier_i2c: slave did not return ACK\n");
 106                ret = -EREMOTEIO;
 107        }
 108        return ret;
 109}
 110
 111static int uniphier_i2c_transmit(struct uniphier_i2c_dev *dev, uint addr,
 112                                 uint len, const u8 *buf, bool *stop)
 113{
 114        int ret;
 115
 116        debug("%s: addr = %x, len = %d\n", __func__, addr, len);
 117
 118        ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
 119        if (ret < 0)
 120                goto fail;
 121
 122        while (len--) {
 123                ret = send_byte(dev, I2C_DTRM_NACK | *buf++, stop);
 124                if (ret < 0)
 125                        goto fail;
 126        }
 127
 128fail:
 129        if (*stop)
 130                writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
 131
 132        return ret;
 133}
 134
 135static int uniphier_i2c_receive(struct uniphier_i2c_dev *dev, uint addr,
 136                                uint len, u8 *buf, bool *stop)
 137{
 138        int ret;
 139
 140        debug("%s: addr = %x, len = %d\n", __func__, addr, len);
 141
 142        ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK |
 143                        I2C_DTRM_RD | addr << 1, stop);
 144        if (ret < 0)
 145                goto fail;
 146
 147        while (len--)
 148                *buf++ = send_and_recv_byte(dev, len ? 0 : I2C_DTRM_NACK);
 149
 150fail:
 151        if (*stop)
 152                writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
 153
 154        return ret;
 155}
 156
 157static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
 158                             int nmsgs)
 159{
 160        int ret = 0;
 161        struct uniphier_i2c_dev *dev = dev_get_priv(bus);
 162        bool stop;
 163
 164        for (; nmsgs > 0; nmsgs--, msg++) {
 165                /* If next message is read, skip the stop condition */
 166                stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
 167
 168                if (msg->flags & I2C_M_RD)
 169                        ret = uniphier_i2c_receive(dev, msg->addr, msg->len,
 170                                                   msg->buf, &stop);
 171                else
 172                        ret = uniphier_i2c_transmit(dev, msg->addr, msg->len,
 173                                                    msg->buf, &stop);
 174
 175                if (ret < 0)
 176                        break;
 177        }
 178
 179        return ret;
 180}
 181
 182static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 183{
 184        struct uniphier_i2c_dev *priv = dev_get_priv(bus);
 185
 186        /* max supported frequency is 400 kHz */
 187        if (speed > 400000)
 188                return -EINVAL;
 189
 190        /* bus reset: make sure the bus is idle when change the frequency */
 191        writel(0x1, &priv->regs->brst);
 192
 193        writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
 194               &priv->regs->clk);
 195
 196        writel(0x3, &priv->regs->brst);
 197
 198        /*
 199         * Theoretically, each byte can be transferred in
 200         * 1000000 * 9 / speed usec.  For safety, wait more than double.
 201         */
 202        priv->wait_us = 20000000 / speed;
 203
 204        return 0;
 205}
 206
 207
 208static const struct dm_i2c_ops uniphier_i2c_ops = {
 209        .xfer = uniphier_i2c_xfer,
 210        .set_bus_speed = uniphier_i2c_set_bus_speed,
 211};
 212
 213static const struct udevice_id uniphier_i2c_of_match[] = {
 214        { .compatible = "socionext,uniphier-i2c" },
 215        { /* sentinel */ }
 216};
 217
 218U_BOOT_DRIVER(uniphier_i2c) = {
 219        .name = "uniphier-i2c",
 220        .id = UCLASS_I2C,
 221        .of_match = uniphier_i2c_of_match,
 222        .probe = uniphier_i2c_probe,
 223        .remove = uniphier_i2c_remove,
 224        .priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev),
 225        .ops = &uniphier_i2c_ops,
 226};
 227