text: /* dw_i2c.c - I2C file for Design Ware */
  
  /*
   * Copyright (c) 2015 Intel Corporation
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  #include <stddef.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <stdbool.h>
  
  #include <i2c.h>
  #include <kernel.h>
  #include <init.h>
  #include <arch/cpu.h>
  #include <string.h>
  
  #include <board.h>
  #include <errno.h>
  #include <sys_io.h>
  
  #include <misc/util.h>
  
  #ifdef CONFIG_SHARED_IRQ
  #include <shared_irq.h>
  #endif
  
  #ifdef CONFIG_IOAPIC
  #include <drivers/ioapic.h>
  #endif
  
  #include "i2c_dw.h"
  #include "i2c_dw_registers.h"
  
  #define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
  #include <logging/sys_log.h>
  
  static inline void _i2c_dw_data_ask(struct device *dev)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	uint32_t data;
  	uint8_t tx_empty;
  	int8_t rx_empty;
  	uint8_t cnt;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	/* No more bytes to request, so command queue is no longer needed */
  	if (dw->request_bytes == 0) {
  		regs->ic_intr_mask.bits.tx_empty = 0;
  		return;
  	}
  
  	/* How many bytes we can actually ask */
  	rx_empty = (I2C_DW_FIFO_DEPTH - regs->ic_rxflr) - dw->rx_pending;
  
  	if (rx_empty < 0) {
  		/* RX FIFO expected to be full.
  		 * So don't request any bytes, yet.
  		 */
  		return;
  	}
  
  	/* How many empty slots in TX FIFO (as command queue) */
  	tx_empty = I2C_DW_FIFO_DEPTH - regs->ic_txflr;
  
  	/* Figure out how many bytes we can request */
  	cnt = min(I2C_DW_FIFO_DEPTH, dw->request_bytes);
  	cnt = min(min(tx_empty, rx_empty), cnt);
  
  	while (cnt > 0) {
  		/* Tell controller to get another byte */
  		data = IC_DATA_CMD_CMD;
  
  		/* Send RESTART if needed */
  		if (dw->xfr_flags & I2C_MSG_RESTART) {
  			data |= IC_DATA_CMD_RESTART;
  			dw->xfr_flags &= ~(I2C_MSG_RESTART);
  		}
  
  		/* After receiving the last byte, send STOP if needed */
  		if ((dw->xfr_flags & I2C_MSG_STOP)
  		    && (dw->request_bytes == 1)) {
  			data |= IC_DATA_CMD_STOP;
  		}
  
  		regs->ic_data_cmd.raw = data;
  
  		dw->rx_pending++;
  		dw->request_bytes--;
  		cnt--;
  	}
  }
  
  static void _i2c_dw_data_read(struct device *dev)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	while (regs->ic_status.bits.rfne && (dw->xfr_len > 0)) {
  		dw->xfr_buf[0] = regs->ic_data_cmd.raw;
  
  		dw->xfr_buf++;
  		dw->xfr_len--;
  		dw->rx_pending--;
  
  		if (dw->xfr_len == 0) {
  			break;
  		}
  	}
  
  	/* Nothing to receive anymore */
  	if (dw->xfr_len == 0) {
  		dw->state &= ~I2C_DW_CMD_RECV;
  		return;
  	}
  }
  
  
  static int _i2c_dw_data_send(struct device *dev)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	uint32_t data = 0;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	/* Nothing to send anymore, mask the interrupt */
  	if (dw->xfr_len == 0) {
  		regs->ic_intr_mask.bits.tx_empty = 0;
  
  		dw->state &= ~I2C_DW_CMD_SEND;
  
  		return 0;
  	}
  
  	while (regs->ic_status.bits.tfnf && (dw->xfr_len > 0)) {
  		/* We have something to transmit to a specific host */
  		data = dw->xfr_buf[0];
  
  		/* Send RESTART if needed */
  		if (dw->xfr_flags & I2C_MSG_RESTART) {
  			data |= IC_DATA_CMD_RESTART;
  			dw->xfr_flags &= ~(I2C_MSG_RESTART);
  		}
  
  		/* Send STOP if needed */
  		if ((dw->xfr_len == 1) && (dw->xfr_flags & I2C_MSG_STOP)) {
  			data |= IC_DATA_CMD_STOP;
  		}
  
  		regs->ic_data_cmd.raw = data;
  
  		dw->xfr_len--;
  		dw->xfr_buf++;
  
  		if (regs->ic_intr_stat.bits.tx_abrt) {
  			return -EIO;
  		}
  	}
  
  	return 0;
  }
  
  static inline void _i2c_dw_transfer_complete(struct device *dev)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	uint32_t value;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	regs->ic_intr_mask.raw = DW_DISABLE_ALL_I2C_INT;
  	value = regs->ic_clr_intr;
  
  	k_sem_give(&dw->device_sync_sem);
  }
  
  static void i2c_dw_isr(void *arg)
  {
  	struct device *port = (struct device *)arg;
  	struct i2c_dw_dev_config * const dw = port->driver_data;
  	union ic_interrupt_register intr_stat;
  	uint32_t value;
  	int ret = 0;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	/* Cache ic_intr_stat for processing, so there is no need to read
  	 * the register multiple times.
  	 */
  	intr_stat.raw = regs->ic_intr_stat.raw;
  
  #if CONFIG_SHARED_IRQ
  	/* If using with shared IRQ, this function will be called
  	 * by the shared IRQ driver. So check here if the interrupt
  	 * is coming from the I2C controller (or somewhere else).
  	 */
  	if (!intr_stat.raw) {
  		return;
  	}
  #endif
  
  	/*
  	 * Causes of an interrupt:
  	 *   - STOP condition is detected
  	 *   - Transfer is aborted
  	 *   - Transmit FIFO is empty
  	 *   - Transmit FIFO has overflowed
  	 *   - Receive FIFO is full
  	 *   - Receive FIFO has overflowed
  	 *   - Received FIFO has underrun
  	 *   - Transmit data is required (tx_req)
  	 *   - Receive data is available (rx_avail)
  	 */
  
  	SYS_LOG_DBG("I2C: interrupt received");
  
  	/* Check if we are configured as a master device */
  	if (regs->ic_con.bits.master_mode) {
  		/* Bail early if there is any error. */
  		if ((DW_INTR_STAT_TX_ABRT | DW_INTR_STAT_TX_OVER |
  		     DW_INTR_STAT_RX_OVER | DW_INTR_STAT_RX_UNDER) &
  		    intr_stat.raw) {
  			dw->state = I2C_DW_CMD_ERROR;
  			goto done;
  		}
  
  		/* Check if the RX FIFO reached threshold */
  		if (intr_stat.bits.rx_full) {
  			_i2c_dw_data_read(port);
  		}
  
  		/* Check if the TX FIFO is ready for commands.
  		 * TX FIFO also serves as command queue where read requests
  		 * are written to TX FIFO.
  		 */
  		if (intr_stat.bits.tx_empty) {
  			if ((dw->xfr_flags & I2C_MSG_RW_MASK)
  			    == I2C_MSG_WRITE) {
  				ret = _i2c_dw_data_send(port);
  			} else {
  				_i2c_dw_data_ask(port);
  			}
  
  			/* If STOP is not expected, finish processing this
  			 * message if there is nothing left to do anymore.
  			 */
  			if (((dw->xfr_len == 0)
  			     && !(dw->xfr_flags & I2C_MSG_STOP))
  			    || (ret != 0)) {
  				goto done;
  			}
  		}
  	} else { /* we must be configured as a slave device */
  
  		/* We have a read requested by the master device */
  		if (intr_stat.bits.rd_req &&
  		    (!dw->app_config.bits.is_slave_read)) {
  
  			/* data is not ready to send */
  			if (intr_stat.bits.tx_abrt) {
  				/* clear the TX_ABRT interrupt */
  				value = regs->ic_clr_tx_abrt;
  			}
  
  			_i2c_dw_data_send(port);
  			value = regs->ic_clr_rd_req;
  		}
  
  		/* The slave device is ready to receive */
  		if (intr_stat.bits.rx_full &&
  		    dw->app_config.bits.is_slave_read) {
  			_i2c_dw_data_read(port);
  		}
  	}
  
  	/* STOP detected: finish processing this message */
  	if (intr_stat.bits.stop_det) {
  		value = regs->ic_clr_stop_det;
  		goto done;
  	}
  
  	return;
  
  done:
  	_i2c_dw_transfer_complete(port);
  }
  
  
  static int _i2c_dw_setup(struct device *dev, uint16_t slave_address)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	uint32_t value;
  	union ic_con_register ic_con;
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	ic_con.raw = 0;
  
  	/* Disable the device controller to be able set TAR */
  	regs->ic_enable.bits.enable = 0;
  
  	/* Disable interrupts */
  	regs->ic_intr_mask.raw = 0;
  
  	/* Clear interrupts */
  	value = regs->ic_clr_intr;
  
  	/* Set master or slave mode - (initialization = slave) */
  	if (dw->app_config.bits.is_master_device) {
  		/*
  		 * Make sure to set both the master_mode and slave_disable_bit
  		 * to both 0 or both 1
  		 */
  		SYS_LOG_DBG("I2C: host configured as Master Device");
  		ic_con.bits.master_mode = 1;
  		ic_con.bits.slave_disable = 1;
  	}
  
  	ic_con.bits.restart_en = 1;
  
  	/* Set addressing mode - (initialization = 7 bit) */
  	if (dw->app_config.bits.use_10_bit_addr) {
  		SYS_LOG_DBG("I2C: using 10-bit address");
  		ic_con.bits.addr_master_10bit = 1;
  		ic_con.bits.addr_slave_10bit = 1;
  	}
  
  	/* Setup the clock frequency and speed mode */
  	switch (dw->app_config.bits.speed) {
  	case I2C_SPEED_STANDARD:
  		SYS_LOG_DBG("I2C: speed set to STANDARD");
  		regs->ic_ss_scl_lcnt = dw->lcnt;
  		regs->ic_ss_scl_hcnt = dw->hcnt;
  		ic_con.bits.speed = I2C_DW_SPEED_STANDARD;
  
  		break;
  	case I2C_SPEED_FAST:
  		/* fall through */
  	case I2C_SPEED_FAST_PLUS:
  		SYS_LOG_DBG("I2C: speed set to FAST or FAST_PLUS");
  		regs->ic_fs_scl_lcnt = dw->lcnt;
  		regs->ic_fs_scl_hcnt = dw->hcnt;
  		ic_con.bits.speed = I2C_DW_SPEED_FAST;
  
  		break;
  	case I2C_SPEED_HIGH:
  		if (!dw->support_hs_mode) {
  			return -EINVAL;
  		}
  
  		SYS_LOG_DBG("I2C: speed set to HIGH");
  		regs->ic_hs_scl_lcnt = dw->lcnt;
  		regs->ic_hs_scl_hcnt = dw->hcnt;
  		ic_con.bits.speed = I2C_DW_SPEED_HIGH;
  
  		break;
  	default:
  		SYS_LOG_DBG("I2C: invalid speed requested");
  		return -EINVAL;
  	}
  
  	SYS_LOG_DBG("I2C: lcnt = %d", dw->lcnt);
  	SYS_LOG_DBG("I2C: hcnt = %d", dw->hcnt);
  
  	/* Set the IC_CON register */
  	regs->ic_con = ic_con;
  
  	/* Set RX fifo threshold level.
  	 * Setting it to zero automatically triggers interrupt
  	 * RX_FULL whenever there is data received.
  	 *
  	 * TODO: extend the threshold for multi-byte RX.
  	 */
  	regs->ic_rx_tl = 0;
  
  	/* Set TX fifo threshold level.
  	 * TX_EMPTY interrupt is triggered only when the
  	 * TX FIFO is truly empty. So that we can let
  	 * the controller do the transfers for longer period
  	 * before we need to fill the FIFO again. This may
  	 * cause some pauses during transfers, but this keeps
  	 * the device from interrupting often.
  	 */
  	regs->ic_tx_tl = 0;
  
  	if (regs->ic_con.bits.master_mode) {
  		/* Set address of target slave */
  		regs->ic_tar.bits.ic_tar = slave_address;
  	} else {
  		/* Set slave address for device */
  		regs->ic_sar.bits.ic_sar = slave_address;
  	}
  
  	return 0;
  }
  
  static int i2c_dw_transfer(struct device *dev,
  			   struct i2c_msg *msgs, uint8_t num_msgs,
  			   uint16_t slave_address)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	struct i2c_msg *cur_msg = msgs;
  	uint8_t msg_left = num_msgs;
  	uint8_t pflags;
  	int ret;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	__ASSERT_NO_MSG(msgs);
  	if (!num_msgs) {
  		return 0;
  	}
  
  	/* First step, check if there is current activity */
  	if ((regs->ic_status.bits.activity) || (dw->state & I2C_DW_BUSY)) {
  		return -EIO;
  	}
  
  	dw->state |= I2C_DW_BUSY;
  
  	ret = _i2c_dw_setup(dev, slave_address);
  	if (ret) {
  		dw->state = I2C_DW_STATE_READY;
  		return ret;
  	}
  
  	/* Enable controller */
  	regs->ic_enable.bits.enable = 1;
  
  	/*
  	 * While waiting at device_sync_sem, kernel can switch to idle
  	 * task which in turn can call _sys_soc_suspend() hook of Power
  	 * Management App (PMA).
  	 * device_busy_set() call here, would indicate to PMA that it should not
  	 * execute PM policies that would turn off this ip block, causing an
  	 * ongoing hw transaction to be left in an inconsistent state.
  	 * Note : This is just a sample to show a possible use of the API, it is
  	 * upto the driver expert to see, if he actually needs it here, or
  	 * somewhere else, or not needed as the driver's suspend()/resume()
  	 * can handle everything
  	 */
  	device_busy_set(dev);
  
  		/* Process all the messages */
  	while (msg_left > 0) {
  		pflags = dw->xfr_flags;
  
  		dw->xfr_buf = cur_msg->buf;
  		dw->xfr_len = cur_msg->len;
  		dw->xfr_flags = cur_msg->flags;
  		dw->rx_pending = 0;
  
  		/* Need to RESTART if changing transfer direction */
  		if ((pflags & I2C_MSG_RW_MASK)
  		    != (dw->xfr_flags & I2C_MSG_RW_MASK)) {
  			dw->xfr_flags |= I2C_MSG_RESTART;
  		}
  
  		/* Send STOP if this is the last message */
  		if (msg_left == 1) {
  			dw->xfr_flags |= I2C_MSG_STOP;
  		}
  
  		dw->state &= ~(I2C_DW_CMD_SEND | I2C_DW_CMD_RECV);
  
  		if ((dw->xfr_flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
  			dw->state |= I2C_DW_CMD_SEND;
  			dw->request_bytes = 0;
  		} else {
  			dw->state |= I2C_DW_CMD_RECV;
  			dw->request_bytes = dw->xfr_len;
  		}
  
  		/* Enable interrupts to trigger ISR */
  		if (regs->ic_con.bits.master_mode) {
  			/* Enable necessary interrupts */
  			regs->ic_intr_mask.raw = (DW_ENABLE_TX_INT_I2C_MASTER |
  						  DW_ENABLE_RX_INT_I2C_MASTER);
  		} else {
  			/* Enable necessary interrupts */
  			regs->ic_intr_mask.raw = DW_ENABLE_TX_INT_I2C_SLAVE;
  		}
  
  		/* Wait for transfer to be done */
  		k_sem_take(&dw->device_sync_sem, K_FOREVER);
  
  		if (dw->state & I2C_DW_CMD_ERROR) {
  			ret = -EIO;
  			break;
  		}
  
  		/* Something wrong if there is something left to do */
  		if (dw->xfr_len > 0) {
  			ret = -EIO;
  			break;
  		}
  
  		cur_msg++;
  		msg_left--;
  	}
  
  	device_busy_clear(dev);
  
  	dw->state = I2C_DW_STATE_READY;
  
  	return ret;
  }
  
  static int i2c_dw_runtime_configure(struct device *dev, uint32_t config)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  	uint32_t	value = 0;
  	uint32_t	rc = 0;
  
  	volatile struct i2c_dw_registers * const regs =
  		(struct i2c_dw_registers *)dw->base_address;
  
  	dw->app_config.raw = config;
  
  	/* Make sure we have a supported speed for the DesignWare model */
  	/* and have setup the clock frequency and speed mode */
  	switch (dw->app_config.bits.speed) {
  	case I2C_SPEED_STANDARD:
  		/* Following the directions on DW spec page 59, IC_SS_SCL_LCNT
  		 * must have register values larger than IC_FS_SPKLEN + 7
  		 */
  		if (I2C_STD_LCNT <= (regs->ic_fs_spklen + 7)) {
  			value = regs->ic_fs_spklen + 8;
  		} else {
  			value = I2C_STD_LCNT;
  		}
  
  		dw->lcnt = value;
  
  		/* Following the directions on DW spec page 59, IC_SS_SCL_HCNT
  		 * must have register values larger than IC_FS_SPKLEN + 5
  		 */
  		if (I2C_STD_HCNT <= (regs->ic_fs_spklen + 5)) {
  			value = regs->ic_fs_spklen + 6;
  		} else {
  			value = I2C_STD_HCNT;
  		}
  
  		dw->hcnt = value;
  		break;
  	case I2C_SPEED_FAST:
  		/* fall through */
  	case I2C_SPEED_FAST_PLUS:
  		/*
  		 * Following the directions on DW spec page 59, IC_FS_SCL_LCNT
  		 * must have register values larger than IC_FS_SPKLEN + 7
  		 */
  		if (I2C_FS_LCNT <= (regs->ic_fs_spklen + 7)) {
  			value = regs->ic_fs_spklen + 8;
  		} else {
  			value = I2C_FS_LCNT;
  		}
  
  		dw->lcnt = value;
  
  		/*
  		 * Following the directions on DW spec page 59, IC_FS_SCL_HCNT
  		 * must have register values larger than IC_FS_SPKLEN + 5
  		 */
  		if (I2C_FS_HCNT <= (regs->ic_fs_spklen + 5)) {
  			value = regs->ic_fs_spklen + 6;
  		} else {
  			value = I2C_FS_HCNT;
  		}
  
  		dw->hcnt = value;
  		break;
  	case I2C_SPEED_HIGH:
  		if (dw->support_hs_mode) {
  			if (I2C_HS_LCNT <= (regs->ic_hs_spklen + 7)) {
  				value = regs->ic_hs_spklen + 8;
  			} else {
  				value = I2C_HS_LCNT;
  			}
  
  			dw->lcnt = value;
  
  			if (I2C_HS_HCNT <= (regs->ic_hs_spklen + 5)) {
  				value = regs->ic_hs_spklen + 6;
  			} else {
  				value = I2C_HS_HCNT;
  			}
  
  			dw->hcnt = value;
  		} else {
  			rc = -EINVAL;
  		}
  		break;
  	default:
  		/* TODO change */
  		rc = -EINVAL;
  	}
  
  	/*
  	 * Clear any interrupts currently waiting in the controller
  	 */
  	value = regs->ic_clr_intr;
  
  	/*
  	 * TEMPORARY HACK - The I2C does not work in any mode other than Master
  	 * currently.  This "hack" forces us to always be configured for master
  	 * mode, until we can verify that Slave mode works correctly.
  	 */
  	dw->app_config.bits.is_master_device = 1;
  
  	return rc;
  }
  
  static const struct i2c_driver_api funcs = {
  	.configure = i2c_dw_runtime_configure,
  	.transfer = i2c_dw_transfer,
  };
  
  
  #ifdef CONFIG_PCI
  static inline int i2c_dw_pci_setup(struct device *dev)
  {
  	struct i2c_dw_dev_config * const dw = dev->driver_data;
  
  	pci_bus_scan_init();
  
  	if (!pci_bus_scan(&dw->pci_dev)) {
  		SYS_LOG_DBG("Could not find device");
  		return 0;
  	}
  
  #ifdef CONFIG_PCI_ENUMERATION
  	dw->base_address = dw->pci_dev.addr;
  #endif
  	pci_enable_regs(&dw->pci_dev);
  
  	pci_show(&dw->pci_dev);
  
  	return 1;
  }
  #else
  #define i2c_dw_pci_setup(_unused_) (1)
  #endif /* CONFIG_PCI */
  
  static int i2c_dw_initialize(struct device *port)
  {
  	const struct i2c_dw_rom_config * const rom = port->config->config_info;
  	struct i2c_dw_dev_config * const dev = port->driver_data;
  
  	volatile struct i2c_dw_registers *regs;
  
  	if (!i2c_dw_pci_setup(port)) {
  		port->driver_api = NULL;
  		return -EIO;
  	}
  
  	k_sem_init(&dev->device_sync_sem, 0, UINT_MAX);
  
  	regs = (struct i2c_dw_registers *) dev->base_address;
  
  	/* verify that we have a valid DesignWare register first */
  	if (regs->ic_comp_type != I2C_DW_MAGIC_KEY) {
  		port->driver_api = NULL;
  		SYS_LOG_DBG("I2C: DesignWare magic key not found, check base "
  			    "address. Stopping initialization");
  		return -EIO;
  	}
  
  	/*
  	 * grab the default value on initialization.  This should be set to the
  	 * IC_MAX_SPEED_MODE in the hardware.  If it does support high speed we
  	 * can move provide support for it
  	 */
  	if (regs->ic_con.bits.speed == I2C_DW_SPEED_HIGH) {
  		SYS_LOG_DBG("I2C: high speed supported");
  		dev->support_hs_mode = true;
  	} else {
  		SYS_LOG_DBG("I2C: high speed NOT supported");
  		dev->support_hs_mode = false;
  	}
  
  	rom->config_func(port);
  
  	if (i2c_dw_runtime_configure(port, dev->app_config.raw) != 0) {
  		SYS_LOG_DBG("I2C: Cannot set default configuration 0x%x",
  		    dev->app_config.raw);
  		return -EIO;
  	}
  
  	dev->state = I2C_DW_STATE_READY;
  
  	return 0;
  }
  
  /* system bindings */
  #if CONFIG_I2C_0
  static void i2c_config_0(struct device *port);
  
  static const struct i2c_dw_rom_config i2c_config_dw_0 = {
  #ifdef CONFIG_I2C_DW_0_IRQ_DIRECT
  	.irq_num = I2C_DW_0_IRQ,
  #endif
  	.config_func = i2c_config_0,
  
  #ifdef CONFIG_GPIO_DW_0_IRQ_SHARED
  	.shared_irq_dev_name = CONFIG_I2C_DW_0_IRQ_SHARED_NAME,
  #endif
  };
  
  static struct i2c_dw_dev_config i2c_0_runtime = {
  	.base_address = I2C_DW_0_BASE_ADDR,
  	.app_config.raw = CONFIG_I2C_0_DEFAULT_CFG,
  #if CONFIG_PCI
  	.pci_dev.class_type = I2C_DW_PCI_CLASS,
  	.pci_dev.bus = I2C_DW_0_PCI_BUS,
  	.pci_dev.dev = I2C_DW_0_PCI_DEV,
  	.pci_dev.vendor_id = I2C_DW_PCI_VENDOR_ID,
  	.pci_dev.device_id = I2C_DW_PCI_DEVICE_ID,
  	.pci_dev.function = I2C_DW_0_PCI_FUNCTION,
  	.pci_dev.bar = I2C_DW_0_PCI_BAR,
  #endif
  };
  
  DEVICE_AND_API_INIT(i2c_0, CONFIG_I2C_0_NAME, &i2c_dw_initialize,
  		    &i2c_0_runtime, &i2c_config_dw_0,
  		    POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,
  		    &funcs);
  
  static void i2c_config_0(struct device *port)
  {
  #if defined(CONFIG_I2C_DW_0_IRQ_DIRECT)
  	IRQ_CONNECT(I2C_DW_0_IRQ, CONFIG_I2C_0_IRQ_PRI,
  		    i2c_dw_isr, DEVICE_GET(i2c_0), I2C_DW_IRQ_FLAGS);
  	irq_enable(I2C_DW_0_IRQ);
  #elif defined(CONFIG_I2C_DW_0_IRQ_SHARED)
  	const struct i2c_dw_rom_config * const config =
  		port->config->config_info;
  	struct device *shared_irq_dev;
  
  	shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
  	shared_irq_isr_register(shared_irq_dev, (isr_t)i2c_dw_isr, port);
  	shared_irq_enable(shared_irq_dev, port);
  #endif
  }
  #endif /* CONFIG_I2C_0 */
  
  
  /*
   * Adding in I2C1
   */
  #if CONFIG_I2C_1
  static void i2c_config_1(struct device *port);
  
  static const struct i2c_dw_rom_config i2c_config_dw_1 = {
  	.irq_num = I2C_DW_1_IRQ,
  	.config_func = i2c_config_1,
  };
  
  static struct i2c_dw_dev_config i2c_1_runtime = {
  	.base_address = I2C_DW_1_BASE_ADDR,
  	.app_config.raw = CONFIG_I2C_1_DEFAULT_CFG,
  
  #if CONFIG_PCI
  	.pci_dev.class_type = I2C_DW_PCI_CLASS,
  	.pci_dev.bus = I2C_DW_1_PCI_BUS,
  	.pci_dev.dev = I2C_DW_1_PCI_DEV,
  	.pci_dev.vendor_id = I2C_DW_PCI_VENDOR_ID,
  	.pci_dev.device_id = I2C_DW_PCI_DEVICE_ID,
  	.pci_dev.function = I2C_DW_1_PCI_FUNCTION,
  	.pci_dev.bar = I2C_DW_1_PCI_BAR,
  #endif
  };
  
  DEVICE_AND_API_INIT(i2c_1, CONFIG_I2C_1_NAME, &i2c_dw_initialize,
  		    &i2c_1_runtime, &i2c_config_dw_1,
  		    POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
  		    &funcs);
  
  static void i2c_config_1(struct device *port)
  {
  	IRQ_CONNECT(I2C_DW_1_IRQ, CONFIG_I2C_1_IRQ_PRI,
  		    i2c_dw_isr, DEVICE_GET(i2c_1), I2C_DW_IRQ_FLAGS);
  	irq_enable(I2C_DW_1_IRQ);
  }
  
  #endif /* CONFIG_I2C_1 */
  