text: /* Copyright 2013 The Chromium OS Authors. All rights reserved.
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  /* I2C port module for Chrome EC */
  
  #include "atomic.h"
  #include "clock.h"
  #include "common.h"
  #include "console.h"
  #include "gpio.h"
  #include "hooks.h"
  #include "i2c.h"
  #include "registers.h"
  #include "task.h"
  #include "timer.h"
  #include "util.h"
  
  #define CPUTS(outstr) cputs(CC_I2C, outstr)
  #define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
  
  /* Flags for writes to MCS */
  #define LM4_I2C_MCS_RUN   BIT(0)
  #define LM4_I2C_MCS_START BIT(1)
  #define LM4_I2C_MCS_STOP  BIT(2)
  #define LM4_I2C_MCS_ACK   BIT(3)
  #define LM4_I2C_MCS_HS    BIT(4)
  #define LM4_I2C_MCS_QCMD  BIT(5)
  
  /* Flags for reads from MCS */
  #define LM4_I2C_MCS_BUSY   BIT(0)
  #define LM4_I2C_MCS_ERROR  BIT(1)
  #define LM4_I2C_MCS_ADRACK BIT(2)
  #define LM4_I2C_MCS_DATACK BIT(3)
  #define LM4_I2C_MCS_ARBLST BIT(4)
  #define LM4_I2C_MCS_IDLE   BIT(5)
  #define LM4_I2C_MCS_BUSBSY BIT(6)
  #define LM4_I2C_MCS_CLKTO  BIT(7)
  
  /*
   * Minimum delay between resetting the port or sending a stop condition, and
   * when the port can be expected to be back in an idle state (and the slave
   * has had long enough to see the start/stop condition edges).
   *
   * 500 us = 50 clocks at 100 KHz bus speed.  This has been experimentally
   * determined to be enough.
   */
  #define I2C_IDLE_US 500
  
  /* IRQ for each port */
  static const uint32_t i2c_irqs[] = {LM4_IRQ_I2C0, LM4_IRQ_I2C1, LM4_IRQ_I2C2,
  				    LM4_IRQ_I2C3, LM4_IRQ_I2C4, LM4_IRQ_I2C5};
  BUILD_ASSERT(ARRAY_SIZE(i2c_irqs) == I2C_PORT_COUNT);
  
  /* I2C port state data */
  struct i2c_port_data {
  	const uint8_t *out;	/* Output data pointer */
  	int out_size;		/* Output data to transfer, in bytes */
  	uint8_t *in;		/* Input data pointer */
  	int in_size;		/* Input data to transfer, in bytes */
  	int flags;		/* Flags (I2C_XFER_*) */
  	int idx;		/* Index into input/output data */
  	int err;		/* Error code, if any */
  	uint32_t timeout_us;	/* Transaction timeout, or 0 to use default */
  
  	/* Task waiting on port, or TASK_ID_INVALID if none. */
  	volatile int task_waiting;
  };
  static struct i2c_port_data pdata[I2C_PORT_COUNT];
  
  int i2c_is_busy(int port)
  {
  	return LM4_I2C_MCS(port) & LM4_I2C_MCS_BUSBSY;
  }
  
  /**
   * I2C transfer engine.
   *
   * @return Zero when done with transfer (ready to wake task).
   *
   * MCS sequence on multi-byte write:
   *     0x3 0x1 0x1 ... 0x1 0x5
   * Single byte write:
   *     0x7
   *
   * MCS receive sequence on multi-byte read:
   *     0xb 0x9 0x9 ... 0x9 0x5
   * Single byte read:
   *     0x7
   */
  int i2c_do_work(int port)
  {
  	struct i2c_port_data *pd = pdata + port;
  	uint32_t reg_mcs = LM4_I2C_MCS_RUN;
  
  	if (pd->flags & I2C_XFER_START) {
  		/* Set start bit on first byte */
  		reg_mcs |= LM4_I2C_MCS_START;
  		pd->flags &= ~I2C_XFER_START;
  	} else if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST |
  					LM4_I2C_MCS_ERROR)) {
  		/*
  		 * Error after starting; abort transfer.  Ignore errors at
  		 * start because arbitration and timeout errors are taken care
  		 * of in chip_i2c_xfer(), and slave ack failures will
  		 * automatically clear once we send a start condition.
  		 */
  		pd->err = EC_ERROR_UNKNOWN;
  		return 0;
  	}
  
  	if (pd->out_size) {
  		/* Send next byte of output */
  		LM4_I2C_MDR(port) = *(pd->out++);
  		pd->idx++;
  
  		/* Handle starting to send last byte */
  		if (pd->idx == pd->out_size) {
  
  			/* Done with output after this */
  			pd->out_size = 0;
  			pd->idx = 0;
  
  			/* Resend start bit when changing direction */
  			pd->flags |= I2C_XFER_START;
  
  			/*
  			 * Send stop bit after last byte if the stop flag is
  			 * on, and caller doesn't expect to receive data.
  			 */
  			if ((pd->flags & I2C_XFER_STOP) && pd->in_size == 0)
  				reg_mcs |= LM4_I2C_MCS_STOP;
  		}
  
  		LM4_I2C_MCS(port) = reg_mcs;
  		return 1;
  
  	} else if (pd->in_size) {
  		if (pd->idx) {
  			/* Copy the byte we just read */
  			*(pd->in++) = LM4_I2C_MDR(port) & 0xff;
  		} else {
  			/* Starting receive; switch to receive address */
  			LM4_I2C_MSA(port) |= 0x01;
  		}
  
  		if (pd->idx < pd->in_size) {
  			/* More data to read */
  			pd->idx++;
  
  			/* ACK all bytes except the last one */
  			if ((pd->flags & I2C_XFER_STOP) &&
  			    pd->idx == pd->in_size)
  				reg_mcs |= LM4_I2C_MCS_STOP;
  			else
  				reg_mcs |= LM4_I2C_MCS_ACK;
  
  			LM4_I2C_MCS(port) = reg_mcs;
  			return 1;
  		}
  	}
  
  	/* If we're still here, done with transfer */
  	return 0;
  }
  
  int chip_i2c_xfer(const int port, const uint16_t slave_addr_flags,
  		  const uint8_t *out, int out_size,
  		  uint8_t *in, int in_size, int flags)
  {
  	struct i2c_port_data *pd = pdata + port;
  	uint32_t reg_mcs = LM4_I2C_MCS(port);
  	int events = 0;
  
  	if (out_size == 0 && in_size == 0)
  		return EC_SUCCESS;
  
  	/* Copy data to port struct */
  	pd->out = out;
  	pd->out_size = out_size;
  	pd->in = in;
  	pd->in_size = in_size;
  	pd->flags = flags;
  	pd->idx = 0;
  	pd->err = 0;
  
  	/* Make sure we're in a good state to start */
  	if ((flags & I2C_XFER_START) &&
  	    ((reg_mcs & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST)) ||
  			    (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
  		uint32_t tpr = LM4_I2C_MTPR(port);
  
  		CPRINTS("I2C%d Addr:%02X bad status 0x%02x, SCL=%d, SDA=%d",
  			port,
  			I2C_GET_ADDR(slave_addr_flags),
  			reg_mcs,
  			i2c_get_line_levels(port) & I2C_LINE_SCL_HIGH,
  			i2c_get_line_levels(port) & I2C_LINE_SDA_HIGH);
  
  		/* Attempt to unwedge the port. */
  		i2c_unwedge(port);
  
  		/* Clock timeout or arbitration lost.  Reset port to clear. */
  		deprecated_atomic_or(LM4_SYSTEM_SRI2C_ADDR, BIT(port));
  		clock_wait_cycles(3);
  		deprecated_atomic_clear_bits(LM4_SYSTEM_SRI2C_ADDR, BIT(port));
  		clock_wait_cycles(3);
  
  		/* Restore settings */
  		LM4_I2C_MCR(port) = 0x10;
  		LM4_I2C_MTPR(port) = tpr;
  
  		/*
  		 * We don't know what edges the slave saw, so sleep long enough
  		 * that the slave will see the new start condition below.
  		 */
  		usleep(I2C_IDLE_US);
  	}
  
  	/* Set slave address for transmit */
  	LM4_I2C_MSA(port) = (I2C_GET_ADDR(slave_addr_flags) << 1) & 0xff;
  
  	/* Enable interrupts */
  	pd->task_waiting = task_get_current();
  	LM4_I2C_MICR(port) = 0x03;
  	LM4_I2C_MIMR(port) = 0x03;
  
  	/* Kick the port interrupt handler to start the transfer */
  	task_trigger_irq(i2c_irqs[port]);
  
  	/* Wait for transfer complete or timeout */
  	events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, pd->timeout_us);
  
  	/* Disable interrupts */
  	LM4_I2C_MIMR(port) = 0x00;
  	pd->task_waiting = TASK_ID_INVALID;
  
  	/* Handle timeout */
  	if (events & TASK_EVENT_TIMER)
  		pd->err = EC_ERROR_TIMEOUT;
  
  	if (pd->err) {
  		/* Force port back idle */
  		LM4_I2C_MCS(port) = LM4_I2C_MCS_STOP;
  		usleep(I2C_IDLE_US);
  	}
  
  	return pd->err;
  }
  
  int i2c_raw_get_scl(int port)
  {
  	enum gpio_signal g;
  	int ret;
  
  	/* If no SCL pin defined for this port, then return 1 to appear idle. */
  	if (get_scl_from_i2c_port(port, &g) != EC_SUCCESS)
  		return 1;
  
  	/* If we are driving the pin low, it must be low. */
  	if (gpio_get_level(g) == 0)
  		return 0;
  
  	/*
  	 * Otherwise, we need to toggle it to an input to read the true pin
  	 * state.
  	 */
  	gpio_set_flags(g, GPIO_INPUT);
  	ret = gpio_get_level(g);
  	gpio_set_flags(g, GPIO_ODR_HIGH);
  
  	return ret;
  }
  
  int i2c_raw_get_sda(int port)
  {
  	enum gpio_signal g;
  	int ret;
  
  	/* If no SDA pin defined for this port, then return 1 to appear idle. */
  	if (get_sda_from_i2c_port(port, &g) != EC_SUCCESS)
  		return 1;
  
  	/* If we are driving the pin low, it must be low. */
  	if (gpio_get_level(g) == 0)
  		return 0;
  
  	/*
  	 * Otherwise, we need to toggle it to an input to read the true pin
  	 * state.
  	 */
  	gpio_set_flags(g, GPIO_INPUT);
  	ret = gpio_get_level(g);
  	gpio_set_flags(g, GPIO_ODR_HIGH);
  
  	return ret;
  }
  
  int i2c_get_line_levels(int port)
  {
  	/* Conveniently, MBMON bit BIT(1) is SDA and BIT(0) is SCL. */
  	return LM4_I2C_MBMON(port) & 0x03;
  }
  
  void i2c_set_timeout(int port, uint32_t timeout)
  {
  	pdata[port].timeout_us = timeout ? timeout : I2C_TIMEOUT_DEFAULT_US;
  }
  
  /*****************************************************************************/
  /* Hooks */
  
  static void i2c_freq_changed(void)
  {
  	int freq = clock_get_freq();
  	int i;
  
  	for (i = 0; i < i2c_ports_used; i++) {
  		/*
  		 * From datasheet:
  		 *     SCL_PRD = 2 * (1 + TPR) * (SCL_LP + SCL_HP) * CLK_PRD
  		 *
  		 * so:
  		 *     TPR = SCL_PRD / (2 * (SCL_LP + SCL_HP) * CLK_PRD) - 1
  		 *
  		 * converting from period to frequency:
  		 *     TPR = CLK_FREQ / (SCL_FREQ * 2 * (SCL_LP + SCL_HP)) - 1
  		 */
  		const int d = 2 * (6 + 4) * (i2c_ports[i].kbps * 1000);
  
  		/* Round TPR up, so desired kbps is an upper bound */
  		const int tpr = (freq + d - 1) / d - 1;
  
  #ifdef PRINT_I2C_SPEEDS
  		const int f = freq / (2 * (1 + tpr) * (6 + 4));
  		CPRINTS("I2C%d clk=%d tpr=%d freq=%d",
  			i2c_ports[i].port, freq, tpr, f);
  #endif
  
  		LM4_I2C_MTPR(i2c_ports[i].port) = tpr;
  	}
  }
  DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);
  
  void i2c_init(void)
  {
  	uint32_t mask = 0;
  	int i;
  
  	/* Enable I2C modules in run and sleep modes. */
  	for (i = 0; i < i2c_ports_used; i++)
  		mask |= 1 << i2c_ports[i].port;
  
  	clock_enable_peripheral(CGC_OFFSET_I2C, mask,
  			CGC_MODE_RUN | CGC_MODE_SLEEP);
  
  	/* Configure GPIOs */
  	gpio_config_module(MODULE_I2C, 1);
  
  	/* Initialize ports as master, with interrupts enabled */
  	for (i = 0; i < i2c_ports_used; i++)
  		LM4_I2C_MCR(i2c_ports[i].port) = 0x10;
  
  	/* Set initial clock frequency */
  	i2c_freq_changed();
  
  	/* Enable IRQs; no tasks are waiting on ports */
  	for (i = 0; i < I2C_PORT_COUNT; i++) {
  		pdata[i].task_waiting = TASK_ID_INVALID;
  		task_enable_irq(i2c_irqs[i]);
  
  		/* Use default timeout */
  		i2c_set_timeout(i, 0);
  	}
  }
  
  /**
   * Handle an interrupt on the specified port.
   *
   * @param port		I2C port generating interrupt
   */
  static void handle_interrupt(int port)
  {
  	int id = pdata[port].task_waiting;
  
  	/* Clear the interrupt status */
  	LM4_I2C_MICR(port) = LM4_I2C_MMIS(port);
  
  	/* If no task is waiting, just return */
  	if (id == TASK_ID_INVALID)
  		return;
  
  	/* If done doing work, wake up the task waiting for the transfer */
  	if (!i2c_do_work(port))
  		task_set_event(id, TASK_EVENT_I2C_IDLE, 0);
  }
  
  void i2c0_interrupt(void) { handle_interrupt(0); }
  void i2c1_interrupt(void) { handle_interrupt(1); }
  void i2c2_interrupt(void) { handle_interrupt(2); }
  void i2c3_interrupt(void) { handle_interrupt(3); }
  void i2c4_interrupt(void) { handle_interrupt(4); }
  void i2c5_interrupt(void) { handle_interrupt(5); }
  
  DECLARE_IRQ(LM4_IRQ_I2C0, i2c0_interrupt, 2);
  DECLARE_IRQ(LM4_IRQ_I2C1, i2c1_interrupt, 2);
  DECLARE_IRQ(LM4_IRQ_I2C2, i2c2_interrupt, 2);
  DECLARE_IRQ(LM4_IRQ_I2C3, i2c3_interrupt, 2);
  DECLARE_IRQ(LM4_IRQ_I2C4, i2c4_interrupt, 2);
  DECLARE_IRQ(LM4_IRQ_I2C5, i2c5_interrupt, 2);
  