From ce1b9ed132427980e65e4ad2b56cd67285876aad Mon Sep 17 00:00:00 2001 From: bertrik Date: Mon, 21 Jun 2010 21:41:07 +0000 Subject: [PATCH] Apply FS #11423 - Use udelay in AMS driver for FM radio I2C git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27035 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/generic_i2c.c | 94 +++++++++++------------ firmware/export/generic_i2c.h | 33 ++++----- firmware/target/arm/as3525/fmradio-i2c-as3525.c | 99 +++++++++++-------------- 3 files changed, 105 insertions(+), 121 deletions(-) diff --git a/firmware/drivers/generic_i2c.c b/firmware/drivers/generic_i2c.c index 87e9091a3..effb5372b 100644 --- a/firmware/drivers/generic_i2c.c +++ b/firmware/drivers/generic_i2c.c @@ -32,55 +32,51 @@ static const struct i2c_interface *i2c_if[MAX_I2C_INTERFACES]; static void i2c_start(const struct i2c_interface *iface) { - iface->sda_output(); - - iface->sda_hi(); - iface->scl_hi(); - iface->delay_su_sta(); - iface->sda_lo(); - iface->delay_hd_sta(); - iface->scl_lo(); - iface->delay_hd_dat(); + iface->sda_dir(true); + + iface->sda_out(1); + iface->scl_out(1); + iface->delay(iface->delay_su_sta); + iface->sda_out(0); + iface->delay(iface->delay_hd_sta); + iface->scl_out(0); + iface->delay(iface->delay_hd_dat); } static void i2c_stop(const struct i2c_interface *iface) { - iface->sda_output(); + iface->sda_dir(true); - iface->sda_lo(); - iface->delay_su_dat(); - iface->scl_hi(); - iface->delay_su_sto(); - iface->sda_hi(); + iface->sda_out(0); + iface->delay(iface->delay_su_dat); + iface->scl_out(1); + iface->delay(iface->delay_su_sto); + iface->sda_out(1); } static void i2c_ack(const struct i2c_interface *iface, bool ack) { - iface->sda_output(); - if ( ack ) - iface->sda_lo(); - else - iface->sda_hi(); - - iface->delay_su_dat(); - iface->scl_hi(); - iface->delay_thigh(); - iface->scl_lo(); - iface->delay_hd_dat(); + iface->sda_dir(true); + iface->sda_out(!ack); + iface->delay(iface->delay_su_dat); + iface->scl_out(1); + iface->delay(iface->delay_thigh); + iface->scl_out(0); + iface->delay(iface->delay_hd_dat); } static int i2c_getack(const struct i2c_interface *iface) { int ret = 1; - iface->sda_input(); - iface->delay_su_dat(); - iface->scl_hi(); - iface->delay_thigh(); - if (iface->sda()) + iface->sda_dir(false); + iface->delay(iface->delay_su_dat); + iface->scl_out(1); + iface->delay(iface->delay_thigh); + if (iface->sda_in()) ret = 0; /* ack failed */ - iface->scl_lo(); - iface->delay_hd_dat(); + iface->scl_out(0); + iface->delay(iface->delay_hd_dat); return ret; } @@ -89,17 +85,17 @@ static unsigned char i2c_inb(const struct i2c_interface *iface, bool ack) int i; unsigned char byte = 0; - iface->sda_input(); + iface->sda_dir(false); /* clock in each bit, MSB first */ for ( i=0x80; i; i>>=1 ) { - iface->delay_su_dat(); - iface->scl_hi(); - iface->delay_thigh(); - if (iface->sda()) + iface->delay(iface->delay_su_dat); + iface->scl_out(1); + iface->delay(iface->delay_thigh); + if (iface->sda_in()) byte |= i; - iface->scl_lo(); - iface->delay_hd_dat(); + iface->scl_out(0); + iface->delay(iface->delay_hd_dat); } i2c_ack(iface, ack); @@ -111,18 +107,16 @@ static int i2c_outb(const struct i2c_interface *iface, unsigned char byte) { int i; - iface->sda_output(); + iface->sda_dir(true); /* clock out each bit, MSB first */ for (i=0x80; i; i>>=1) { - if (i & byte) - iface->sda_hi(); - else - iface->sda_lo(); - iface->delay_su_dat(); - iface->scl_hi(); - iface->delay_thigh(); - iface->scl_lo(); + iface->sda_out(i & byte); + iface->delay(iface->delay_su_dat); + iface->scl_out(1); + iface->delay(iface->delay_thigh); + iface->scl_out(0); + iface->delay(iface->delay_hd_dat); } return i2c_getack(iface); @@ -215,7 +209,7 @@ int i2c_add_node(const struct i2c_interface *iface) bus_index = i2c_num_ifs++; i2c_if[bus_index] = iface; - iface->scl_output(); + iface->scl_dir(true); return bus_index; } diff --git a/firmware/export/generic_i2c.h b/firmware/export/generic_i2c.h index 6679b7841..f71736acf 100644 --- a/firmware/export/generic_i2c.h +++ b/firmware/export/generic_i2c.h @@ -21,27 +21,26 @@ #ifndef _GEN_I2C_ #define _GEN_I2C_ +#include + struct i2c_interface { - void (*scl_hi)(void); /* Drive SCL high, might sleep on clk stretch */ - void (*scl_lo)(void); /* Drive SCL low */ - void (*sda_hi)(void); /* Drive SDA high */ - void (*sda_lo)(void); /* Drive SDA low */ - void (*sda_input)(void); /* Set SDA as input */ - void (*sda_output)(void); /* Set SDA as output */ - void (*scl_input)(void); /* Set SCL as input */ - void (*scl_output)(void); /* Set SCL as output */ - int (*scl)(void); /* Read SCL, returns 0 or non-zero */ - int (*sda)(void); /* Read SDA, returns 0 or non-zero */ - + void (*scl_dir)(bool out); /* Set SCL as input or output */ + void (*sda_dir)(bool out); /* Set SDA as input or output */ + void (*scl_out)(bool high); /* Drive SCL, might sleep on clk stretch */ + void (*sda_out)(bool high); /* Drive SDA */ + bool (*scl_in)(void); /* Read SCL, returns true if high */ + bool (*sda_in)(void); /* Read SDA, returns true if high */ + void (*delay)(int delay); /* Delay for the specified amount */ + /* These are the delays specified in the I2C specification, the time pairs to the right are the minimum 100kHz and 400kHz specs */ - void (*delay_hd_sta)(void); /* START SDA hold (tHD:SDA) 4.0us/0.6us */ - void (*delay_hd_dat)(void); /* SDA hold (tHD:DAT) 5.0us/0us */ - void (*delay_su_dat)(void); /* SDA setup (tSU:DAT) 250ns/100ns */ - void (*delay_su_sto)(void); /* STOP setup (tSU:STO) 4.0us/0.6us */ - void (*delay_su_sta)(void); /* Rep. START setup (tSU:STA) 4.7us/0.6us */ - void (*delay_thigh)(void); /* SCL high period (tHIGH) 4.0us/0.6us */ + int delay_hd_sta; /* START SDA hold (tHD:SDA) 4.0us/0.6us */ + int delay_hd_dat; /* SDA hold (tHD:DAT) 5.0us/0us */ + int delay_su_dat; /* SDA setup (tSU:DAT) 250ns/100ns */ + int delay_su_sto; /* STOP setup (tSU:STO) 4.0us/0.6us */ + int delay_su_sta; /* Rep. START setup (tSU:STA) 4.7us/0.6us */ + int delay_thigh; /* SCL high period (tHIGH) 4.0us/0.6us */ }; int i2c_add_node(const struct i2c_interface *iface); diff --git a/firmware/target/arm/as3525/fmradio-i2c-as3525.c b/firmware/target/arm/as3525/fmradio-i2c-as3525.c index 33d12f9fa..9e8dc6314 100644 --- a/firmware/target/arm/as3525/fmradio-i2c-as3525.c +++ b/firmware/target/arm/as3525/fmradio-i2c-as3525.c @@ -28,6 +28,7 @@ */ #include "as3525.h" +#include "system.h" #include "generic_i2c.h" #include "fmradio_i2c.h" @@ -77,85 +78,75 @@ static int fm_i2c_bus; -static void fm_scl_hi(void) +static void fm_scl_dir(bool out) { - I2C_SCL_GPIO(I2C_SCL_PIN) = 1 << I2C_SCL_PIN; -} - -static void fm_scl_lo(void) -{ - I2C_SCL_GPIO(I2C_SCL_PIN) = 0; -} - -static void fm_sda_hi(void) -{ - I2C_SDA_GPIO(I2C_SDA_PIN) = 1 << I2C_SDA_PIN; -} - -static void fm_sda_lo(void) -{ - I2C_SDA_GPIO(I2C_SDA_PIN) = 0; + if (out) { + I2C_SCL_GPIO_DIR |= 1 << I2C_SCL_PIN; + } else { + I2C_SCL_GPIO_DIR &= ~(1 << I2C_SCL_PIN); + } } -static void fm_sda_input(void) +static void fm_sda_dir(bool out) { - I2C_SDA_GPIO_DIR &= ~(1 << I2C_SDA_PIN); + if (out) { + I2C_SDA_GPIO_DIR |= 1 << I2C_SDA_PIN; + } else { + I2C_SDA_GPIO_DIR &= ~(1 << I2C_SDA_PIN); + } } -static void fm_sda_output(void) +static void fm_scl_out(bool level) { - I2C_SDA_GPIO_DIR |= 1 << I2C_SDA_PIN; + if (level) { + I2C_SCL_GPIO(I2C_SCL_PIN) = 1 << I2C_SCL_PIN; + } else { + I2C_SCL_GPIO(I2C_SCL_PIN) = 0; + } } -static void fm_scl_input(void) +static void fm_sda_out(bool level) { - I2C_SCL_GPIO_DIR &= ~(1 << I2C_SCL_PIN); + if (level) { + I2C_SDA_GPIO(I2C_SDA_PIN) = 1 << I2C_SDA_PIN; + } else { + I2C_SDA_GPIO(I2C_SDA_PIN) = 0; + } } -static void fm_scl_output(void) +static bool fm_scl_in(void) { - I2C_SCL_GPIO_DIR |= 1 << I2C_SCL_PIN; + return I2C_SCL_GPIO(I2C_SCL_PIN); } -static int fm_sda(void) +static bool fm_sda_in(void) { return I2C_SDA_GPIO(I2C_SDA_PIN); } -static int fm_scl(void) +static void fm_delay(int delay) { - return I2C_SCL_GPIO(I2C_SCL_PIN); -} - -/* simple and crude delay, used for all delays in the generic i2c driver */ -static void fm_delay(void) -{ - volatile int i; - - /* this loop is uncalibrated and could use more sophistication */ - for (i = 0; i < 20; i++) { + if (delay != 0) { + udelay(delay); } } /* interface towards the generic i2c driver */ static const struct i2c_interface fm_i2c_interface = { - .scl_hi = fm_scl_hi, - .scl_lo = fm_scl_lo, - .sda_hi = fm_sda_hi, - .sda_lo = fm_sda_lo, - .sda_input = fm_sda_input, - .sda_output = fm_sda_output, - .scl_input = fm_scl_input, - .scl_output = fm_scl_output, - .scl = fm_scl, - .sda = fm_sda, - - .delay_hd_sta = fm_delay, - .delay_hd_dat = fm_delay, - .delay_su_dat = fm_delay, - .delay_su_sto = fm_delay, - .delay_su_sta = fm_delay, - .delay_thigh = fm_delay + .scl_out = fm_scl_out, + .scl_dir = fm_scl_dir, + .sda_out = fm_sda_out, + .sda_dir = fm_sda_dir, + .sda_in = fm_sda_in, + .scl_in = fm_scl_in, + .delay = fm_delay, + + .delay_hd_sta = 1, + .delay_hd_dat = 0, + .delay_su_dat = 1, + .delay_su_sto = 1, + .delay_su_sta = 1, + .delay_thigh = 2 }; /* initialise i2c for fmradio */ -- 2.11.4.GIT