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