145 lines
3.3 KiB
C
145 lines
3.3 KiB
C
|
/* 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 slave 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 master 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 slave 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 */
|
||
|
}
|