]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/i2c/tegra_i2c.c
i2c: tegra: Build warning fixes for 64-bit
[people/ms/u-boot.git] / drivers / i2c / tegra_i2c.c
index 594e5ddeb43ee8a64dc4e7956cb1d6e44bfd4d12..a4289788a65cb7ae8e9583a03299c2b1b992ef41 100644 (file)
@@ -7,6 +7,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum i2c_type {
+       TYPE_114,
+       TYPE_STD,
+       TYPE_DVC,
+};
+
 /* Information about i2c controller */
 struct i2c_bus {
        int                     id;
@@ -27,20 +35,17 @@ struct i2c_bus {
        int                     pinmux_config;
        struct i2c_control      *control;
        struct i2c_ctlr         *regs;
-       int                     is_dvc; /* DVC type, rather than I2C */
-       int                     is_scs; /* single clock source (T114+) */
+       enum i2c_type           type;
        int                     inited; /* bus is inited */
 };
 
-static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
-
 static void set_packet_mode(struct i2c_bus *i2c_bus)
 {
        u32 config;
 
        config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
 
-       if (i2c_bus->is_dvc) {
+       if (i2c_bus->type == TYPE_DVC) {
                struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
                writel(config, &dvc->cnfg);
@@ -65,6 +70,9 @@ static void i2c_reset_controller(struct i2c_bus *i2c_bus)
 
 static void i2c_init_controller(struct i2c_bus *i2c_bus)
 {
+       if (!i2c_bus->speed)
+               return;
+       debug("%s: speed=%d\n", __func__, i2c_bus->speed);
        /*
         * Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
         * here, in section 23.3.1, but in fact we seem to need a factor of
@@ -73,7 +81,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
        clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
                i2c_bus->speed * 2 * 8);
 
-       if (i2c_bus->is_scs) {
+       if (i2c_bus->type == TYPE_114) {
                /*
                 * T114 I2C went to a single clock source for standard/fast and
                 * HS clock speeds. The new clock rate setting calculation is:
@@ -98,7 +106,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
        i2c_reset_controller(i2c_bus);
 
        /* Configure I2C controller. */
-       if (i2c_bus->is_dvc) {  /* only for DVC I2C */
+       if (i2c_bus->type == TYPE_DVC) {        /* only for DVC I2C */
                struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
                setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
@@ -110,7 +118,8 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
 static void send_packet_headers(
        struct i2c_bus *i2c_bus,
        struct i2c_trans_info *trans,
-       u32 packet_id)
+       u32 packet_id,
+       bool end_with_repeated_start)
 {
        u32 data;
 
@@ -132,6 +141,8 @@ static void send_packet_headers(
        /* Enable Read if it is not a write transaction */
        if (!(trans->flags & I2C_IS_WRITE))
                data |= PKT_HDR3_READ_MODE_MASK;
+       if (end_with_repeated_start)
+               data |= PKT_HDR3_REPEAT_START_MASK;
 
        /* Write I2C specific header */
        writel(data, &i2c_bus->control->tx_fifo);
@@ -209,7 +220,8 @@ static int send_recv_packets(struct i2c_bus *i2c_bus,
        int_status = readl(&control->int_status);
        writel(int_status, &control->int_status);
 
-       send_packet_headers(i2c_bus, trans, 1);
+       send_packet_headers(i2c_bus, trans, 1,
+                           trans->flags & I2C_USE_REPEATED_START);
 
        words = DIV_ROUND_UP(trans->num_bytes, 4);
        last_bytes = trans->num_bytes & 3;
@@ -220,14 +232,16 @@ static int send_recv_packets(struct i2c_bus *i2c_bus,
 
                if (is_write) {
                        /* deal with word alignment */
-                       if ((unsigned)dptr & 3) {
+                       if ((words == 1) && last_bytes) {
+                               local = 0;
+                               memcpy(&local, dptr, last_bytes);
+                       } else if ((unsigned long)dptr & 3) {
                                memcpy(&local, dptr, sizeof(u32));
-                               writel(local, &control->tx_fifo);
-                               debug("pkt data sent (0x%x)\n", local);
                        } else {
-                               writel(*wptr, &control->tx_fifo);
-                               debug("pkt data sent (0x%x)\n", *wptr);
+                               local = *wptr;
                        }
+                       writel(local, &control->tx_fifo);
+                       debug("pkt data sent (0x%x)\n", local);
                        if (!wait_for_tx_fifo_empty(control)) {
                                error = -1;
                                goto exit;
@@ -244,7 +258,7 @@ static int send_recv_packets(struct i2c_bus *i2c_bus,
                        local = readl(&control->rx_fifo);
                        if ((words == 1) && last_bytes)
                                memcpy(dptr, (char *)&local, last_bytes);
-                       else if ((unsigned)dptr & 3)
+                       else if ((unsigned long)dptr & 3)
                                memcpy(dptr, &local, sizeof(u32));
                        else
                                *wptr = local;
@@ -266,8 +280,8 @@ exit:
        return error;
 }
 
-static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
-                               u32 len)
+static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
+                               u32 len, bool end_with_repeated_start)
 {
        int error;
        struct i2c_trans_info trans_info;
@@ -275,17 +289,19 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
        trans_info.address = addr;
        trans_info.buf = data;
        trans_info.flags = I2C_IS_WRITE;
+       if (end_with_repeated_start)
+               trans_info.flags |= I2C_USE_REPEATED_START;
        trans_info.num_bytes = len;
        trans_info.is_10bit_address = 0;
 
-       error = send_recv_packets(bus, &trans_info);
+       error = send_recv_packets(i2c_bus, &trans_info);
        if (error)
                debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
 
        return error;
 }
 
-static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
                               u32 len)
 {
        int error;
@@ -297,52 +313,32 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
        trans_info.num_bytes = len;
        trans_info.is_10bit_address = 0;
 
-       error = send_recv_packets(bus, &trans_info);
+       error = send_recv_packets(i2c_bus, &trans_info);
        if (error)
                debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
 
        return error;
 }
 
-#ifndef CONFIG_OF_CONTROL
-#error "Please enable device tree support to use this driver"
-#endif
-
-/**
- * Check that a bus number is valid and return a pointer to it
- *
- * @param bus_num      Bus number to check / return
- * @return pointer to bus, if valid, else NULL
- */
-static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap)
-{
-       struct i2c_bus *bus;
-
-       bus = &i2c_controllers[adap->hwadapnr];
-       if (!bus->inited) {
-               debug("%s: Bus %u not available\n", __func__, adap->hwadapnr);
-               return NULL;
-       }
-
-       return bus;
-}
-
-static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap,
-                       unsigned int speed)
+static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 {
-       struct i2c_bus *bus;
+       struct i2c_bus *i2c_bus = dev_get_priv(dev);
 
-       bus = tegra_i2c_get_bus(adap);
-       if (!bus)
-               return 0;
-       bus->speed = speed;
-       i2c_init_controller(bus);
+       i2c_bus->speed = speed;
+       i2c_init_controller(i2c_bus);
 
        return 0;
 }
 
-static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
+static int tegra_i2c_probe(struct udevice *dev)
 {
+       struct i2c_bus *i2c_bus = dev_get_priv(dev);
+       const void *blob = gd->fdt_blob;
+       int node = dev->of_offset;
+       bool is_dvc;
+
+       i2c_bus->id = dev->seq;
+       i2c_bus->type = dev_get_driver_data(dev);
        i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
 
        /*
@@ -350,7 +346,6 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
         * far no one needs anything other than the default.
         */
        i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
-       i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
        i2c_bus->periph_id = clock_decode_periph_id(blob, node);
 
        /*
@@ -363,107 +358,26 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
         *              i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
         */
        if (i2c_bus->periph_id == -1)
-               return -FDT_ERR_NOTFOUND;
+               return -EINVAL;
 
-       return 0;
-}
-
-/*
- * Process a list of nodes, adding them to our list of I2C ports.
- *
- * @param blob         fdt blob
- * @param node_list    list of nodes to process (any <=0 are ignored)
- * @param count                number of nodes to process
- * @param is_dvc       1 if these are DVC ports, 0 if standard I2C
- * @param is_scs       1 if this HW uses a single clock source (T114+)
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count,
-                        int is_dvc, int is_scs)
-{
-       struct i2c_bus *i2c_bus;
-       int i;
-
-       /* build the i2c_controllers[] for each controller */
-       for (i = 0; i < count; i++) {
-               int node = node_list[i];
-
-               if (node <= 0)
-                       continue;
-
-               i2c_bus = &i2c_controllers[i];
-               i2c_bus->id = i;
-
-               if (i2c_get_config(blob, node, i2c_bus)) {
-                       printf("i2c_init_board: failed to decode bus %d\n", i);
-                       return -1;
-               }
-
-               i2c_bus->is_scs = is_scs;
-
-               i2c_bus->is_dvc = is_dvc;
-               if (is_dvc) {
-                       i2c_bus->control =
-                               &((struct dvc_ctlr *)i2c_bus->regs)->control;
-               } else {
-                       i2c_bus->control = &i2c_bus->regs->control;
-               }
-               debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
-                     is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
-                     i2c_bus->periph_id, i2c_bus->speed);
-               i2c_init_controller(i2c_bus);
-               debug("ok\n");
-               i2c_bus->inited = 1;
-
-               /* Mark position as used */
-               node_list[i] = -1;
+       is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
+       if (is_dvc) {
+               i2c_bus->control =
+                       &((struct dvc_ctlr *)i2c_bus->regs)->control;
+       } else {
+               i2c_bus->control = &i2c_bus->regs->control;
        }
+       i2c_init_controller(i2c_bus);
+       debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
+             is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
+             i2c_bus->periph_id, i2c_bus->speed);
 
        return 0;
 }
 
-/* Sadly there is no error return from this function */
-void i2c_init_board(void)
-{
-       int node_list[TEGRA_I2C_NUM_CONTROLLERS];
-       const void *blob = gd->fdt_blob;
-       int count;
-
-       /* First check for newer (T114+) I2C ports */
-       count = fdtdec_find_aliases_for_id(blob, "i2c",
-                       COMPAT_NVIDIA_TEGRA114_I2C, node_list,
-                       TEGRA_I2C_NUM_CONTROLLERS);
-       if (process_nodes(blob, node_list, count, 0, 1))
-               return;
-
-       /* Now get the older (T20/T30) normal I2C ports */
-       count = fdtdec_find_aliases_for_id(blob, "i2c",
-                       COMPAT_NVIDIA_TEGRA20_I2C, node_list,
-                       TEGRA_I2C_NUM_CONTROLLERS);
-       if (process_nodes(blob, node_list, count, 0, 0))
-               return;
-
-       /* Now look for dvc ports */
-       count = fdtdec_add_aliases_for_id(blob, "i2c",
-                       COMPAT_NVIDIA_TEGRA20_DVC, node_list,
-                       TEGRA_I2C_NUM_CONTROLLERS);
-       if (process_nodes(blob, node_list, count, 1, 0))
-               return;
-}
-
-static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
-       /* No i2c support prior to relocation */
-       if (!(gd->flags & GD_FLG_RELOC))
-               return;
-
-       /* This will override the speed selected in the fdt for that port */
-       debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
-       i2c_set_bus_speed(speed);
-}
-
 /* i2c write version without the register address */
-int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
+static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+                         int len, bool end_with_repeated_start)
 {
        int rc;
 
@@ -475,7 +389,8 @@ int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
        debug("\n");
 
        /* Shift 7-bit address over for lower-level i2c functions */
-       rc = tegra_i2c_write_data(bus, chip << 1, buffer, len);
+       rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
+                                 end_with_repeated_start);
        if (rc)
                debug("i2c_write_data(): rc=%d\n", rc);
 
@@ -483,13 +398,14 @@ int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
 }
 
 /* i2c read version without the register address */
-int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
+static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+                        int len)
 {
        int rc;
 
        debug("inside i2c_read_data():\n");
        /* Shift 7-bit address over for lower-level i2c functions */
-       rc = tegra_i2c_read_data(bus, chip << 1, buffer, len);
+       rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
        if (rc) {
                debug("i2c_read_data(): rc=%d\n", rc);
                return rc;
@@ -505,132 +421,81 @@ int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
 }
 
 /* Probe to see if a chip is present. */
-static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+                               uint chip_flags)
 {
-       struct i2c_bus *bus;
+       struct i2c_bus *i2c_bus = dev_get_priv(bus);
        int rc;
-       uchar reg;
-
-       debug("i2c_probe: addr=0x%x\n", chip);
-       bus = tegra_i2c_get_bus(adap);
-       if (!bus)
-               return 1;
-       reg = 0;
-       rc = i2c_write_data(bus, chip, &reg, 1);
-       if (rc) {
-               debug("Error probing 0x%x.\n", chip);
-               return 1;
-       }
-       return 0;
-}
+       u8 reg;
 
-static int i2c_addr_ok(const uint addr, const int alen)
-{
-       /* We support 7 or 10 bit addresses, so one or two bytes each */
-       return alen == 1 || alen == 2;
+       /* Shift 7-bit address over for lower-level i2c functions */
+       rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
+                                 false);
+
+       return rc;
 }
 
-/* Read bytes */
-static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
-                       int alen, uchar *buffer, int len)
+static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+                         int nmsgs)
 {
-       struct i2c_bus *bus;
-       uint offset;
-       int i;
-
-       debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n",
-                               chip, addr, len);
-       bus = tegra_i2c_get_bus(adap);
-       if (!bus)
-               return 1;
-       if (!i2c_addr_ok(addr, alen)) {
-               debug("i2c_read: Bad address %x.%d.\n", addr, alen);
-               return 1;
-       }
-       for (offset = 0; offset < len; offset++) {
-               if (alen) {
-                       uchar data[alen];
-                       for (i = 0; i < alen; i++) {
-                               data[alen - i - 1] =
-                                       (addr + offset) >> (8 * i);
-                       }
-                       if (i2c_write_data(bus, chip, data, alen)) {
-                               debug("i2c_read: error sending (0x%x)\n",
-                                       addr);
-                               return 1;
-                       }
+       struct i2c_bus *i2c_bus = dev_get_priv(bus);
+       int ret;
+
+       debug("i2c_xfer: %d messages\n", nmsgs);
+       for (; nmsgs > 0; nmsgs--, msg++) {
+               bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+               debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+               if (msg->flags & I2C_M_RD) {
+                       ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+                                           msg->len);
+               } else {
+                       ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+                                            msg->len, next_is_read);
                }
-               if (i2c_read_data(bus, chip, buffer + offset, 1)) {
-                       debug("i2c_read: error reading (0x%x)\n", addr);
-                       return 1;
+               if (ret) {
+                       debug("i2c_write: error sending\n");
+                       return -EREMOTEIO;
                }
        }
 
        return 0;
 }
 
-/* Write bytes */
-static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
-                       int alen, uchar *buffer, int len)
+int tegra_i2c_get_dvc_bus(struct udevice **busp)
 {
-       struct i2c_bus *bus;
-       uint offset;
-       int i;
-
-       debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n",
-                               chip, addr, len);
-       bus = tegra_i2c_get_bus(adap);
-       if (!bus)
-               return 1;
-       if (!i2c_addr_ok(addr, alen)) {
-               debug("i2c_write: Bad address %x.%d.\n", addr, alen);
-               return 1;
-       }
-       for (offset = 0; offset < len; offset++) {
-               uchar data[alen + 1];
-               for (i = 0; i < alen; i++)
-                       data[alen - i - 1] = (addr + offset) >> (8 * i);
-               data[alen] = buffer[offset];
-               if (i2c_write_data(bus, chip, data, alen + 1)) {
-                       debug("i2c_write: error sending (0x%x)\n", addr);
-                       return 1;
+       struct udevice *bus;
+
+       for (uclass_first_device(UCLASS_I2C, &bus);
+            bus;
+            uclass_next_device(&bus)) {
+               if (dev_get_driver_data(bus) == TYPE_DVC) {
+                       *busp = bus;
+                       return 0;
                }
        }
 
-       return 0;
+       return -ENODEV;
 }
 
-int tegra_i2c_get_dvc_bus_num(void)
-{
-       int i;
-
-       for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) {
-               struct i2c_bus *bus = &i2c_controllers[i];
-
-               if (bus->inited && bus->is_dvc)
-                       return i;
-       }
+static const struct dm_i2c_ops tegra_i2c_ops = {
+       .xfer           = tegra_i2c_xfer,
+       .probe_chip     = tegra_i2c_probe_chip,
+       .set_bus_speed  = tegra_i2c_set_bus_speed,
+};
 
-       return -1;
-}
+static const struct udevice_id tegra_i2c_ids[] = {
+       { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+       { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
+       { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+       { }
+};
 
-/*
- * Register soft i2c adapters
- */
-U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe,
-                        tegra_i2c_read, tegra_i2c_write,
-                        tegra_i2c_set_bus_speed, 100000, 0, 0)
-U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe,
-                        tegra_i2c_read, tegra_i2c_write,
-                        tegra_i2c_set_bus_speed, 100000, 0, 1)
-U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe,
-                        tegra_i2c_read, tegra_i2c_write,
-                        tegra_i2c_set_bus_speed, 100000, 0, 2)
-U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe,
-                        tegra_i2c_read, tegra_i2c_write,
-                        tegra_i2c_set_bus_speed, 100000, 0, 3)
-#if TEGRA_I2C_NUM_CONTROLLERS > 4
-U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe,
-                        tegra_i2c_read, tegra_i2c_write,
-                        tegra_i2c_set_bus_speed, 100000, 0, 4)
-#endif
+U_BOOT_DRIVER(i2c_tegra) = {
+       .name   = "i2c_tegra",
+       .id     = UCLASS_I2C,
+       .of_match = tegra_i2c_ids,
+       .probe  = tegra_i2c_probe,
+       .priv_auto_alloc_size = sizeof(struct i2c_bus),
+       .ops    = &tegra_i2c_ops,
+};