text: /* Copyright 2012 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.
   */
  
  /* 1-wire interface module for Chrome EC */
  
  #include "common.h"
  #include "gpio.h"
  #include "task.h"
  #include "timer.h"
  
  /*
   * Standard speed; all timings padded by 2 usec for safety.
   *
   * Note that these timing are actually _longer_ than legacy 1-wire standard
   * speed because we're running the 1-wire bus at 3.3V instead of 5V.
   */
  #define T_RSTL 602  /* Reset low pulse; 600-960 us */
  #define T_MSP   72  /* Presence detect sample time; 70-75 us */
  #define T_RSTH (68 + 260 + 5 + 2) /* Reset high; tPDHmax + tPDLmax + tRECmin */
  #define T_SLOT  70  /* Timeslot; >67 us */
  #define T_W0L   63  /* Write 0 low; 62-120 us */
  #define T_W1L    7  /* Write 1 low; 5-15 us */
  #define T_RL     7  /* Read low; 5-15 us */
  #define T_MSR    9  /* Read sample time; <15 us.  Must be at least 200 ns after
  		     * T_RL since that's how long the signal takes to be pulled
  		     * up on our board.  */
  
  /**
   * Output low on the bus for <usec> us, then switch back to open-drain input.
   */
  static void output0(int usec)
  {
  	gpio_set_flags(GPIO_ONEWIRE,
  		       GPIO_OPEN_DRAIN | GPIO_OUTPUT | GPIO_OUT_LOW);
  	udelay(usec);
  	gpio_set_flags(GPIO_ONEWIRE, GPIO_INPUT);
  }
  
  /**
   * Read a bit.
   */
  static int readbit(void)
  {
  	int bit;
  
  	/*
  	 * The delay between sending the output pulse and reading the bit is
  	 * extremely timing sensitive, so disable interrupts.
  	 */
  	interrupt_disable();
  
  	/* Output low */
  	output0(T_RL);
  
  	/*
  	 * Delay to let peripheral release the line if it wants to send
  	 * a 1-bit
  	 */
  	udelay(T_MSR - T_RL);
  
  	/* Read bit */
  	bit = gpio_get_level(GPIO_ONEWIRE);
  
  	/*
  	 * Enable interrupt as soon as we've read the bit.  The delay to the
  	 * end of the timeslot is a lower bound, so additional latency here is
  	 * harmless.
  	 */
  	interrupt_enable();
  
  	/* Delay to end of timeslot */
  	udelay(T_SLOT - T_MSR);
  	return bit;
  }
  
  /**
   * Write a bit.
   */
  static void writebit(int bit)
  {
  	/*
  	 * The delays in the output-low signal for sending 0 and 1 bits are
  	 * extremely timing sensitive, so disable interrupts during that time.
  	 * Interrupts can be enabled again as soon as the output is switched
  	 * back to open-drain, since the delay for the rest of the timeslot is
  	 * a lower bound.
  	 */
  	if (bit) {
  		interrupt_disable();
  		output0(T_W1L);
  		interrupt_enable();
  		udelay(T_SLOT - T_W1L);
  	} else {
  		interrupt_disable();
  		output0(T_W0L);
  		interrupt_enable();
  		udelay(T_SLOT - T_W0L);
  	}
  
  }
  
  int onewire_reset(void)
  {
  	/* Start transaction with controller reset pulse */
  	output0(T_RSTL);
  
  	/* Wait for presence detect sample time.
  	 *
  	 * (Alternately, we could poll waiting for a 1-bit indicating our pulse
  	 * has let go, then poll up to max time waiting for a 0-bit indicating
  	 * the peripheral has responded.)
  	 */
  	udelay(T_MSP);
  
  	if (gpio_get_level(GPIO_ONEWIRE))
  		return EC_ERROR_UNKNOWN;
  
  	/*
  	 * Wait for end of presence pulse.
  	 *
  	 * (Alternately, we could poll waiting for a 1-bit.)
  	 */
  	udelay(T_RSTH - T_MSP);
  
  	return EC_SUCCESS;
  }
  
  int onewire_read(void)
  {
  	int data = 0;
  	int i;
  
  	for (i = 0; i < 8; i++)
  		data |= readbit() << i;  /* LSB first */
  
  	return data;
  }
  
  void onewire_write(int data)
  {
  	int i;
  
  	for (i = 0; i < 8; i++)
  		writebit((data >> i) & 0x01);  /* LSB first */
  }
  