uboot/drivers/i2c/at91_i2c.c
<<
>>
Prefs
   1/*
   2 * Atmel I2C driver.
   3 *
   4 * (C) Copyright 2016 Songjun Wu <songjun.wu@atmel.com>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <asm/io.h>
  10#include <common.h>
  11#include <clk.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <fdtdec.h>
  15#include <i2c.h>
  16#include <linux/bitops.h>
  17#include <mach/clk.h>
  18
  19#include "at91_i2c.h"
  20
  21DECLARE_GLOBAL_DATA_PTR;
  22
  23#define I2C_TIMEOUT_MS  100
  24
  25static int at91_wait_for_xfer(struct at91_i2c_bus *bus, u32 status)
  26{
  27        struct at91_i2c_regs *reg = bus->regs;
  28        ulong start_time = get_timer(0);
  29        u32 sr;
  30
  31        bus->status = 0;
  32
  33        do {
  34                sr = readl(&reg->sr);
  35                bus->status |= sr;
  36
  37                if (sr & TWI_SR_NACK)
  38                        return -EREMOTEIO;
  39                else if (sr & status)
  40                        return 0;
  41        } while (get_timer(start_time) < I2C_TIMEOUT_MS);
  42
  43        return -ETIMEDOUT;
  44}
  45
  46static int at91_i2c_xfer_msg(struct at91_i2c_bus *bus, struct i2c_msg *msg)
  47{
  48        struct at91_i2c_regs *reg = bus->regs;
  49        bool is_read = msg->flags & I2C_M_RD;
  50        u32 i;
  51        int ret = 0;
  52
  53        readl(&reg->sr);
  54        if (is_read) {
  55                writel(TWI_CR_START, &reg->cr);
  56
  57                for (i = 0; !ret && i < (msg->len - 1); i++) {
  58                        ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
  59                        msg->buf[i] = readl(&reg->rhr);
  60                }
  61
  62                if (ret)
  63                        goto error;
  64
  65                writel(TWI_CR_STOP, &reg->cr);
  66
  67                ret = at91_wait_for_xfer(bus, TWI_SR_RXRDY);
  68                if (ret)
  69                        goto error;
  70
  71                msg->buf[i] = readl(&reg->rhr);
  72
  73        } else {
  74                writel(msg->buf[0], &reg->thr);
  75                for (i = 1; !ret && (i < msg->len); i++) {
  76                        writel(msg->buf[i], &reg->thr);
  77                        ret = at91_wait_for_xfer(bus, TWI_SR_TXRDY);
  78                }
  79
  80                if (ret)
  81                        goto error;
  82
  83                writel(TWI_CR_STOP, &reg->cr);
  84        }
  85
  86        if (!ret)
  87                ret = at91_wait_for_xfer(bus, TWI_SR_TXCOMP);
  88
  89        if (ret)
  90                goto error;
  91
  92        if (bus->status & (TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_LOCK)) {
  93                ret = -EIO;
  94                goto error;
  95        }
  96
  97        return 0;
  98
  99error:
 100        if (bus->status & TWI_SR_LOCK)
 101                writel(TWI_CR_LOCKCLR, &reg->cr);
 102
 103        return ret;
 104}
 105
 106static int at91_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
 107{
 108        struct at91_i2c_bus *bus = dev_get_priv(dev);
 109        struct at91_i2c_regs *reg = bus->regs;
 110        struct i2c_msg *m_start = msg;
 111        bool is_read;
 112        u32 int_addr_flag = 0;
 113        int ret = 0;
 114
 115        if (nmsgs == 2) {
 116                int internal_address = 0;
 117                int i;
 118
 119                /* 1st msg is put into the internal address, start with 2nd */
 120                m_start = &msg[1];
 121
 122                /* the max length of internal address is 3 bytes */
 123                if (msg->len > 3)
 124                        return -EFAULT;
 125
 126                for (i = 0; i < msg->len; ++i) {
 127                        const unsigned addr = msg->buf[msg->len - 1 - i];
 128
 129                        internal_address |= addr << (8 * i);
 130                        int_addr_flag += TWI_MMR_IADRSZ_1;
 131                }
 132
 133                writel(internal_address, &reg->iadr);
 134        }
 135
 136        is_read = m_start->flags & I2C_M_RD;
 137
 138        writel((m_start->addr << 16) | int_addr_flag |
 139               (is_read ? TWI_MMR_MREAD : 0), &reg->mmr);
 140
 141        ret = at91_i2c_xfer_msg(bus, m_start);
 142
 143        return ret;
 144}
 145
 146/*
 147 * Calculate symmetric clock as stated in datasheet:
 148 * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
 149 */
 150static void at91_calc_i2c_clock(struct udevice *dev, int i2c_clk)
 151{
 152        struct at91_i2c_bus *bus = dev_get_priv(dev);
 153        const struct at91_i2c_pdata *pdata = bus->pdata;
 154        int offset = pdata->clk_offset;
 155        int max_ckdiv = pdata->clk_max_div;
 156        int ckdiv, cdiv, div;
 157        unsigned long src_rate;
 158
 159        src_rate = bus->bus_clk_rate;
 160
 161        div = max(0, (int)DIV_ROUND_UP(src_rate, 2 * i2c_clk) - offset);
 162        ckdiv = fls(div >> 8);
 163        cdiv = div >> ckdiv;
 164
 165        if (ckdiv > max_ckdiv) {
 166                ckdiv = max_ckdiv;
 167                cdiv = 255;
 168        }
 169
 170        bus->speed = DIV_ROUND_UP(src_rate,
 171                                  (cdiv * (1 << ckdiv) + offset) * 2);
 172
 173        bus->cwgr_val = (ckdiv << 16) | (cdiv << 8) | cdiv;
 174}
 175
 176static int at91_i2c_enable_clk(struct udevice *dev)
 177{
 178        struct at91_i2c_bus *bus = dev_get_priv(dev);
 179        struct clk clk;
 180        ulong clk_rate;
 181        int ret;
 182
 183        ret = clk_get_by_index(dev, 0, &clk);
 184        if (ret)
 185                return -EINVAL;
 186
 187        ret = clk_enable(&clk);
 188        if (ret)
 189                return ret;
 190
 191        clk_rate = clk_get_rate(&clk);
 192        if (!clk_rate)
 193                return -EINVAL;
 194
 195        bus->bus_clk_rate = clk_rate;
 196
 197        clk_free(&clk);
 198
 199        return 0;
 200}
 201
 202static int at91_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
 203{
 204        struct at91_i2c_bus *bus = dev_get_priv(dev);
 205        struct at91_i2c_regs *reg = bus->regs;
 206        int ret;
 207
 208        ret = at91_i2c_enable_clk(dev);
 209        if (ret)
 210                return ret;
 211
 212        writel(TWI_CR_SWRST, &reg->cr);
 213
 214        at91_calc_i2c_clock(dev, bus->clock_frequency);
 215
 216        writel(bus->cwgr_val, &reg->cwgr);
 217        writel(TWI_CR_MSEN, &reg->cr);
 218        writel(TWI_CR_SVDIS, &reg->cr);
 219
 220        return 0;
 221}
 222
 223static int at91_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 224{
 225        struct at91_i2c_bus *bus = dev_get_priv(dev);
 226
 227        at91_calc_i2c_clock(dev, speed);
 228
 229        writel(bus->cwgr_val, &bus->regs->cwgr);
 230
 231        return 0;
 232}
 233
 234int at91_i2c_get_bus_speed(struct udevice *dev)
 235{
 236        struct at91_i2c_bus *bus = dev_get_priv(dev);
 237
 238        return bus->speed;
 239}
 240
 241static int at91_i2c_ofdata_to_platdata(struct udevice *dev)
 242{
 243        const void *blob = gd->fdt_blob;
 244        struct at91_i2c_bus *bus = dev_get_priv(dev);
 245        int node = dev->of_offset;
 246
 247        bus->regs = (struct at91_i2c_regs *)dev_get_addr(dev);
 248        bus->pdata = (struct at91_i2c_pdata *)dev_get_driver_data(dev);
 249        bus->clock_frequency = fdtdec_get_int(blob, node,
 250                                              "clock-frequency", 100000);
 251
 252        return 0;
 253}
 254
 255static const struct dm_i2c_ops at91_i2c_ops = {
 256        .xfer           = at91_i2c_xfer,
 257        .probe_chip     = at91_i2c_probe,
 258        .set_bus_speed  = at91_i2c_set_bus_speed,
 259        .get_bus_speed  = at91_i2c_get_bus_speed,
 260};
 261
 262static const struct at91_i2c_pdata at91rm9200_config = {
 263        .clk_max_div = 5,
 264        .clk_offset = 3,
 265};
 266
 267static const struct at91_i2c_pdata at91sam9261_config = {
 268        .clk_max_div = 5,
 269        .clk_offset = 4,
 270};
 271
 272static const struct at91_i2c_pdata at91sam9260_config = {
 273        .clk_max_div = 7,
 274        .clk_offset = 4,
 275};
 276
 277static const struct at91_i2c_pdata at91sam9g20_config = {
 278        .clk_max_div = 7,
 279        .clk_offset = 4,
 280};
 281
 282static const struct at91_i2c_pdata at91sam9g10_config = {
 283        .clk_max_div = 7,
 284        .clk_offset = 4,
 285};
 286
 287static const struct at91_i2c_pdata at91sam9x5_config = {
 288        .clk_max_div = 7,
 289        .clk_offset = 4,
 290};
 291
 292static const struct at91_i2c_pdata sama5d4_config = {
 293        .clk_max_div = 7,
 294        .clk_offset = 4,
 295};
 296
 297static const struct at91_i2c_pdata sama5d2_config = {
 298        .clk_max_div = 7,
 299        .clk_offset = 3,
 300};
 301
 302static const struct udevice_id at91_i2c_ids[] = {
 303{ .compatible = "atmel,at91rm9200-i2c", .data = (long)&at91rm9200_config },
 304{ .compatible = "atmel,at91sam9260-i2c", .data = (long)&at91sam9260_config },
 305{ .compatible = "atmel,at91sam9261-i2c", .data = (long)&at91sam9261_config },
 306{ .compatible = "atmel,at91sam9g20-i2c", .data = (long)&at91sam9g20_config },
 307{ .compatible = "atmel,at91sam9g10-i2c", .data = (long)&at91sam9g10_config },
 308{ .compatible = "atmel,at91sam9x5-i2c", .data = (long)&at91sam9x5_config },
 309{ .compatible = "atmel,sama5d4-i2c", .data = (long)&sama5d4_config },
 310{ .compatible = "atmel,sama5d2-i2c", .data = (long)&sama5d2_config },
 311{ }
 312};
 313
 314U_BOOT_DRIVER(i2c_at91) = {
 315        .name   = "i2c_at91",
 316        .id     = UCLASS_I2C,
 317        .of_match = at91_i2c_ids,
 318        .ofdata_to_platdata = at91_i2c_ofdata_to_platdata,
 319        .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
 320        .priv_auto_alloc_size = sizeof(struct at91_i2c_bus),
 321        .ops    = &at91_i2c_ops,
 322};
 323