-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
runtime: bit-banged i2c support (untested)
1 parent
73bfbe5
commit 423ca03
Showing
5 changed files
with
214 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
#include <generated/csr.h> | ||
|
||
#include "rtio.h" | ||
#include "i2c.h" | ||
|
||
|
||
static void i2c_halfperiod() | ||
{ | ||
timer_kernel_en_write(0); | ||
timer_kernel_load_write(CONFIG_CLOCK_FREQUENCY/10000); | ||
timer_kernel_reload_write(0); | ||
timer_kernel_en_write(1); | ||
|
||
timer_kernel_update_value_write(1); | ||
while(timer_kernel_value_read() != 0) | ||
timer_kernel_update_value_write(1); | ||
} | ||
|
||
#if (defined CONFIG_I2C_BUS_COUNT) && (CONFIG_I2C_BUS_COUNT > 0) | ||
|
||
#define SDA_BIT (1 << (2*busno + 1)) | ||
#define SCL_BIT (1 << (2*busno)) | ||
|
||
static int i2c_sda_i(int busno) | ||
{ | ||
if(busno >= CONFIG_I2C_BUS_COUNT) | ||
return 1; | ||
else | ||
return i2c_in_read() & SDA_BIT; | ||
} | ||
|
||
static void i2c_sda_oe(int busno, int oe) | ||
{ | ||
int reg; | ||
|
||
reg = i2c_oe_read(); | ||
if(oe) | ||
reg |= SDA_BIT; | ||
else | ||
reg &= ~SDA_BIT; | ||
i2c_oe_write(reg); | ||
} | ||
|
||
static void i2c_sda_o(int busno, int o) | ||
{ | ||
int reg; | ||
|
||
reg = i2c_out_read(); | ||
if(o) | ||
reg |= SDA_BIT; | ||
else | ||
reg &= ~SDA_BIT; | ||
i2c_out_write(reg); | ||
} | ||
|
||
static void i2c_scl_oe(int busno, int oe) | ||
{ | ||
int reg; | ||
|
||
reg = i2c_oe_read(); | ||
if(oe) | ||
reg |= SCL_BIT; | ||
else | ||
reg &= ~SCL_BIT; | ||
i2c_oe_write(reg); | ||
} | ||
|
||
static void i2c_scl_o(int busno, int o) | ||
{ | ||
int reg; | ||
|
||
reg = i2c_out_read(); | ||
if(o) | ||
reg |= SCL_BIT; | ||
else | ||
reg &= ~SCL_BIT; | ||
i2c_out_write(reg); | ||
} | ||
|
||
#else | ||
|
||
static int i2c_sda_i(int busno) | ||
{ | ||
return 1; | ||
} | ||
static void i2c_sda_oe(int busno, int oe) {} | ||
static void i2c_sda_o(int busno, int o) {} | ||
static void i2c_scl_oe(int busno, int oe) {} | ||
static void i2c_scl_o(int busno, int o) {} | ||
|
||
#endif | ||
|
||
|
||
int i2c_init(int busno) | ||
{ | ||
/* Set SCL as output, and high level */ | ||
i2c_scl_o(busno, 1); | ||
i2c_scl_oe(busno, 1); | ||
/* Prepare a zero level on SDA so that i2c_sda_oe pulls it down */ | ||
i2c_sda_o(busno, 0); | ||
/* Release SDA */ | ||
i2c_sda_oe(busno, 0); | ||
|
||
/* Check the I2C bus is ready */ | ||
i2c_halfperiod(); | ||
i2c_halfperiod(); | ||
if(i2c_sda_i(busno)) | ||
return 1; /* success */ | ||
else | ||
return 0; | ||
} | ||
|
||
void i2c_start(int busno) | ||
{ | ||
/* Set SCL high then SDA low */ | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
i2c_sda_oe(busno, 1); | ||
i2c_halfperiod(); | ||
} | ||
|
||
void i2c_stop(int busno) | ||
{ | ||
/* First, make sure SCL is low, so that the target releases the SDA line */ | ||
i2c_scl_o(busno, 0); | ||
i2c_halfperiod(); | ||
/* Set SCL high then SDA high */ | ||
i2c_sda_oe(busno, 1); | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
i2c_sda_oe(busno, 0); | ||
i2c_halfperiod(); | ||
} | ||
|
||
int i2c_write(int busno, char b) | ||
{ | ||
int i; | ||
|
||
/* MSB first */ | ||
for(i=7;i>=0;i--) { | ||
/* Set SCL low and set our bit on SDA */ | ||
i2c_scl_o(busno, 0); | ||
i2c_sda_oe(busno, b & (1 << i) ? 0 : 1); | ||
i2c_halfperiod(); | ||
/* Set SCL high ; data is shifted on the rising edge of SCL */ | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
} | ||
/* Check ack */ | ||
/* Set SCL low, then release SDA so that the I2C target can respond */ | ||
i2c_scl_o(busno, 0); | ||
i2c_halfperiod(); | ||
i2c_sda_oe(busno, 0); | ||
/* Set SCL high and check for ack */ | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
/* returns 1 if acked (I2C target pulled SDA low) */ | ||
return !i2c_sda_i(busno); | ||
} | ||
|
||
char i2c_read(int busno, int ack) | ||
{ | ||
int i; | ||
char b; | ||
|
||
/* Set SCL low first, otherwise setting SDA as input may cause a transition | ||
* on SDA with SCL high which will be interpreted as START/STOP condition. | ||
*/ | ||
i2c_scl_o(busno, 0); | ||
i2c_halfperiod(); /* make sure SCL has settled low */ | ||
i2c_sda_oe(busno, 0); | ||
|
||
b = 0; | ||
/* MSB first */ | ||
for(i=7;i>=0;i--) { | ||
i2c_scl_o(busno, 0); | ||
i2c_halfperiod(); | ||
/* Set SCL high and shift data */ | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
if(i2c_sda_i(busno)) b |= (1 << i); | ||
} | ||
/* Send ack */ | ||
/* Set SCL low and pull SDA low when acking */ | ||
i2c_scl_o(busno, 0); | ||
if(ack) | ||
i2c_sda_oe(busno, 1); | ||
i2c_halfperiod(); | ||
/* then set SCL high */ | ||
i2c_scl_o(busno, 1); | ||
i2c_halfperiod(); | ||
|
||
return b; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef __I2C_H | ||
#define __I2C_H | ||
|
||
int i2c_init(int busno); | ||
void i2c_start(int busno); | ||
void i2c_stop(int busno); | ||
int i2c_write(int busno, char b); | ||
char i2c_read(int busno, int ack); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters