diff options
author | Bertrik Sikken <bertrik@sikken.nl> | 2010-06-21 21:41:07 +0000 |
---|---|---|
committer | Bertrik Sikken <bertrik@sikken.nl> | 2010-06-21 21:41:07 +0000 |
commit | 206227096477f328dfe16fee2d9ec13d631bd6e6 (patch) | |
tree | 0edd9336df4bb217186aa7799a522d3cacebc4f9 | |
parent | 06b9064205d3e8aaf7f743fb1486733dd369ce1c (diff) | |
download | rockbox-206227096477f328dfe16fee2d9ec13d631bd6e6.tar.gz rockbox-206227096477f328dfe16fee2d9ec13d631bd6e6.zip |
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
-rw-r--r-- | firmware/drivers/generic_i2c.c | 94 | ||||
-rw-r--r-- | firmware/export/generic_i2c.h | 33 | ||||
-rw-r--r-- | 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 87e9091a3d..effb5372b4 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]; | |||
32 | 32 | ||
33 | static void i2c_start(const struct i2c_interface *iface) | 33 | static void i2c_start(const struct i2c_interface *iface) |
34 | { | 34 | { |
35 | iface->sda_output(); | 35 | iface->sda_dir(true); |
36 | 36 | ||
37 | iface->sda_hi(); | 37 | iface->sda_out(1); |
38 | iface->scl_hi(); | 38 | iface->scl_out(1); |
39 | iface->delay_su_sta(); | 39 | iface->delay(iface->delay_su_sta); |
40 | iface->sda_lo(); | 40 | iface->sda_out(0); |
41 | iface->delay_hd_sta(); | 41 | iface->delay(iface->delay_hd_sta); |
42 | iface->scl_lo(); | 42 | iface->scl_out(0); |
43 | iface->delay_hd_dat(); | 43 | iface->delay(iface->delay_hd_dat); |
44 | } | 44 | } |
45 | 45 | ||
46 | static void i2c_stop(const struct i2c_interface *iface) | 46 | static void i2c_stop(const struct i2c_interface *iface) |
47 | { | 47 | { |
48 | iface->sda_output(); | 48 | iface->sda_dir(true); |
49 | 49 | ||
50 | iface->sda_lo(); | 50 | iface->sda_out(0); |
51 | iface->delay_su_dat(); | 51 | iface->delay(iface->delay_su_dat); |
52 | iface->scl_hi(); | 52 | iface->scl_out(1); |
53 | iface->delay_su_sto(); | 53 | iface->delay(iface->delay_su_sto); |
54 | iface->sda_hi(); | 54 | iface->sda_out(1); |
55 | } | 55 | } |
56 | 56 | ||
57 | static void i2c_ack(const struct i2c_interface *iface, bool ack) | 57 | static void i2c_ack(const struct i2c_interface *iface, bool ack) |
58 | { | 58 | { |
59 | iface->sda_output(); | 59 | iface->sda_dir(true); |
60 | if ( ack ) | 60 | iface->sda_out(!ack); |
61 | iface->sda_lo(); | 61 | iface->delay(iface->delay_su_dat); |
62 | else | 62 | iface->scl_out(1); |
63 | iface->sda_hi(); | 63 | iface->delay(iface->delay_thigh); |
64 | 64 | iface->scl_out(0); | |
65 | iface->delay_su_dat(); | 65 | iface->delay(iface->delay_hd_dat); |
66 | iface->scl_hi(); | ||
67 | iface->delay_thigh(); | ||
68 | iface->scl_lo(); | ||
69 | iface->delay_hd_dat(); | ||
70 | } | 66 | } |
71 | 67 | ||
72 | static int i2c_getack(const struct i2c_interface *iface) | 68 | static int i2c_getack(const struct i2c_interface *iface) |
73 | { | 69 | { |
74 | int ret = 1; | 70 | int ret = 1; |
75 | 71 | ||
76 | iface->sda_input(); | 72 | iface->sda_dir(false); |
77 | iface->delay_su_dat(); | 73 | iface->delay(iface->delay_su_dat); |
78 | iface->scl_hi(); | 74 | iface->scl_out(1); |
79 | iface->delay_thigh(); | 75 | iface->delay(iface->delay_thigh); |
80 | if (iface->sda()) | 76 | if (iface->sda_in()) |
81 | ret = 0; /* ack failed */ | 77 | ret = 0; /* ack failed */ |
82 | iface->scl_lo(); | 78 | iface->scl_out(0); |
83 | iface->delay_hd_dat(); | 79 | iface->delay(iface->delay_hd_dat); |
84 | return ret; | 80 | return ret; |
85 | } | 81 | } |
86 | 82 | ||
@@ -89,17 +85,17 @@ static unsigned char i2c_inb(const struct i2c_interface *iface, bool ack) | |||
89 | int i; | 85 | int i; |
90 | unsigned char byte = 0; | 86 | unsigned char byte = 0; |
91 | 87 | ||
92 | iface->sda_input(); | 88 | iface->sda_dir(false); |
93 | 89 | ||
94 | /* clock in each bit, MSB first */ | 90 | /* clock in each bit, MSB first */ |
95 | for ( i=0x80; i; i>>=1 ) { | 91 | for ( i=0x80; i; i>>=1 ) { |
96 | iface->delay_su_dat(); | 92 | iface->delay(iface->delay_su_dat); |
97 | iface->scl_hi(); | 93 | iface->scl_out(1); |
98 | iface->delay_thigh(); | 94 | iface->delay(iface->delay_thigh); |
99 | if (iface->sda()) | 95 | if (iface->sda_in()) |
100 | byte |= i; | 96 | byte |= i; |
101 | iface->scl_lo(); | 97 | iface->scl_out(0); |
102 | iface->delay_hd_dat(); | 98 | iface->delay(iface->delay_hd_dat); |
103 | } | 99 | } |
104 | 100 | ||
105 | i2c_ack(iface, ack); | 101 | i2c_ack(iface, ack); |
@@ -111,18 +107,16 @@ static int i2c_outb(const struct i2c_interface *iface, unsigned char byte) | |||
111 | { | 107 | { |
112 | int i; | 108 | int i; |
113 | 109 | ||
114 | iface->sda_output(); | 110 | iface->sda_dir(true); |
115 | 111 | ||
116 | /* clock out each bit, MSB first */ | 112 | /* clock out each bit, MSB first */ |
117 | for (i=0x80; i; i>>=1) { | 113 | for (i=0x80; i; i>>=1) { |
118 | if (i & byte) | 114 | iface->sda_out(i & byte); |
119 | iface->sda_hi(); | 115 | iface->delay(iface->delay_su_dat); |
120 | else | 116 | iface->scl_out(1); |
121 | iface->sda_lo(); | 117 | iface->delay(iface->delay_thigh); |
122 | iface->delay_su_dat(); | 118 | iface->scl_out(0); |
123 | iface->scl_hi(); | 119 | iface->delay(iface->delay_hd_dat); |
124 | iface->delay_thigh(); | ||
125 | iface->scl_lo(); | ||
126 | } | 120 | } |
127 | 121 | ||
128 | return i2c_getack(iface); | 122 | return i2c_getack(iface); |
@@ -215,7 +209,7 @@ int i2c_add_node(const struct i2c_interface *iface) | |||
215 | bus_index = i2c_num_ifs++; | 209 | bus_index = i2c_num_ifs++; |
216 | i2c_if[bus_index] = iface; | 210 | i2c_if[bus_index] = iface; |
217 | 211 | ||
218 | iface->scl_output(); | 212 | iface->scl_dir(true); |
219 | 213 | ||
220 | return bus_index; | 214 | return bus_index; |
221 | } | 215 | } |
diff --git a/firmware/export/generic_i2c.h b/firmware/export/generic_i2c.h index 6679b78415..f71736acf0 100644 --- a/firmware/export/generic_i2c.h +++ b/firmware/export/generic_i2c.h | |||
@@ -21,27 +21,26 @@ | |||
21 | #ifndef _GEN_I2C_ | 21 | #ifndef _GEN_I2C_ |
22 | #define _GEN_I2C_ | 22 | #define _GEN_I2C_ |
23 | 23 | ||
24 | #include <stdbool.h> | ||
25 | |||
24 | struct i2c_interface | 26 | struct i2c_interface |
25 | { | 27 | { |
26 | void (*scl_hi)(void); /* Drive SCL high, might sleep on clk stretch */ | 28 | void (*scl_dir)(bool out); /* Set SCL as input or output */ |
27 | void (*scl_lo)(void); /* Drive SCL low */ | 29 | void (*sda_dir)(bool out); /* Set SDA as input or output */ |
28 | void (*sda_hi)(void); /* Drive SDA high */ | 30 | void (*scl_out)(bool high); /* Drive SCL, might sleep on clk stretch */ |
29 | void (*sda_lo)(void); /* Drive SDA low */ | 31 | void (*sda_out)(bool high); /* Drive SDA */ |
30 | void (*sda_input)(void); /* Set SDA as input */ | 32 | bool (*scl_in)(void); /* Read SCL, returns true if high */ |
31 | void (*sda_output)(void); /* Set SDA as output */ | 33 | bool (*sda_in)(void); /* Read SDA, returns true if high */ |
32 | void (*scl_input)(void); /* Set SCL as input */ | 34 | void (*delay)(int delay); /* Delay for the specified amount */ |
33 | void (*scl_output)(void); /* Set SCL as output */ | 35 | |
34 | int (*scl)(void); /* Read SCL, returns 0 or non-zero */ | ||
35 | int (*sda)(void); /* Read SDA, returns 0 or non-zero */ | ||
36 | |||
37 | /* These are the delays specified in the I2C specification, the | 36 | /* These are the delays specified in the I2C specification, the |
38 | time pairs to the right are the minimum 100kHz and 400kHz specs */ | 37 | time pairs to the right are the minimum 100kHz and 400kHz specs */ |
39 | void (*delay_hd_sta)(void); /* START SDA hold (tHD:SDA) 4.0us/0.6us */ | 38 | int delay_hd_sta; /* START SDA hold (tHD:SDA) 4.0us/0.6us */ |
40 | void (*delay_hd_dat)(void); /* SDA hold (tHD:DAT) 5.0us/0us */ | 39 | int delay_hd_dat; /* SDA hold (tHD:DAT) 5.0us/0us */ |
41 | void (*delay_su_dat)(void); /* SDA setup (tSU:DAT) 250ns/100ns */ | 40 | int delay_su_dat; /* SDA setup (tSU:DAT) 250ns/100ns */ |
42 | void (*delay_su_sto)(void); /* STOP setup (tSU:STO) 4.0us/0.6us */ | 41 | int delay_su_sto; /* STOP setup (tSU:STO) 4.0us/0.6us */ |
43 | void (*delay_su_sta)(void); /* Rep. START setup (tSU:STA) 4.7us/0.6us */ | 42 | int delay_su_sta; /* Rep. START setup (tSU:STA) 4.7us/0.6us */ |
44 | void (*delay_thigh)(void); /* SCL high period (tHIGH) 4.0us/0.6us */ | 43 | int delay_thigh; /* SCL high period (tHIGH) 4.0us/0.6us */ |
45 | }; | 44 | }; |
46 | 45 | ||
47 | int i2c_add_node(const struct i2c_interface *iface); | 46 | 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 33d12f9fa7..9e8dc63144 100644 --- a/firmware/target/arm/as3525/fmradio-i2c-as3525.c +++ b/firmware/target/arm/as3525/fmradio-i2c-as3525.c | |||
@@ -28,6 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include "as3525.h" | 30 | #include "as3525.h" |
31 | #include "system.h" | ||
31 | #include "generic_i2c.h" | 32 | #include "generic_i2c.h" |
32 | #include "fmradio_i2c.h" | 33 | #include "fmradio_i2c.h" |
33 | 34 | ||
@@ -77,85 +78,75 @@ | |||
77 | 78 | ||
78 | static int fm_i2c_bus; | 79 | static int fm_i2c_bus; |
79 | 80 | ||
80 | static void fm_scl_hi(void) | 81 | static void fm_scl_dir(bool out) |
81 | { | 82 | { |
82 | I2C_SCL_GPIO(I2C_SCL_PIN) = 1 << I2C_SCL_PIN; | 83 | if (out) { |
83 | } | 84 | I2C_SCL_GPIO_DIR |= 1 << I2C_SCL_PIN; |
84 | 85 | } else { | |
85 | static void fm_scl_lo(void) | 86 | I2C_SCL_GPIO_DIR &= ~(1 << I2C_SCL_PIN); |
86 | { | 87 | } |
87 | I2C_SCL_GPIO(I2C_SCL_PIN) = 0; | ||
88 | } | ||
89 | |||
90 | static void fm_sda_hi(void) | ||
91 | { | ||
92 | I2C_SDA_GPIO(I2C_SDA_PIN) = 1 << I2C_SDA_PIN; | ||
93 | } | ||
94 | |||
95 | static void fm_sda_lo(void) | ||
96 | { | ||
97 | I2C_SDA_GPIO(I2C_SDA_PIN) = 0; | ||
98 | } | 88 | } |
99 | 89 | ||
100 | static void fm_sda_input(void) | 90 | static void fm_sda_dir(bool out) |
101 | { | 91 | { |
102 | I2C_SDA_GPIO_DIR &= ~(1 << I2C_SDA_PIN); | 92 | if (out) { |
93 | I2C_SDA_GPIO_DIR |= 1 << I2C_SDA_PIN; | ||
94 | } else { | ||
95 | I2C_SDA_GPIO_DIR &= ~(1 << I2C_SDA_PIN); | ||
96 | } | ||
103 | } | 97 | } |
104 | 98 | ||
105 | static void fm_sda_output(void) | 99 | static void fm_scl_out(bool level) |
106 | { | 100 | { |
107 | I2C_SDA_GPIO_DIR |= 1 << I2C_SDA_PIN; | 101 | if (level) { |
102 | I2C_SCL_GPIO(I2C_SCL_PIN) = 1 << I2C_SCL_PIN; | ||
103 | } else { | ||
104 | I2C_SCL_GPIO(I2C_SCL_PIN) = 0; | ||
105 | } | ||
108 | } | 106 | } |
109 | 107 | ||
110 | static void fm_scl_input(void) | 108 | static void fm_sda_out(bool level) |
111 | { | 109 | { |
112 | I2C_SCL_GPIO_DIR &= ~(1 << I2C_SCL_PIN); | 110 | if (level) { |
111 | I2C_SDA_GPIO(I2C_SDA_PIN) = 1 << I2C_SDA_PIN; | ||
112 | } else { | ||
113 | I2C_SDA_GPIO(I2C_SDA_PIN) = 0; | ||
114 | } | ||
113 | } | 115 | } |
114 | 116 | ||
115 | static void fm_scl_output(void) | 117 | static bool fm_scl_in(void) |
116 | { | 118 | { |
117 | I2C_SCL_GPIO_DIR |= 1 << I2C_SCL_PIN; | 119 | return I2C_SCL_GPIO(I2C_SCL_PIN); |
118 | } | 120 | } |
119 | 121 | ||
120 | static int fm_sda(void) | 122 | static bool fm_sda_in(void) |
121 | { | 123 | { |
122 | return I2C_SDA_GPIO(I2C_SDA_PIN); | 124 | return I2C_SDA_GPIO(I2C_SDA_PIN); |
123 | } | 125 | } |
124 | 126 | ||
125 | static int fm_scl(void) | 127 | static void fm_delay(int delay) |
126 | { | 128 | { |
127 | return I2C_SCL_GPIO(I2C_SCL_PIN); | 129 | if (delay != 0) { |
128 | } | 130 | udelay(delay); |
129 | |||
130 | /* simple and crude delay, used for all delays in the generic i2c driver */ | ||
131 | static void fm_delay(void) | ||
132 | { | ||
133 | volatile int i; | ||
134 | |||
135 | /* this loop is uncalibrated and could use more sophistication */ | ||
136 | for (i = 0; i < 20; i++) { | ||
137 | } | 131 | } |
138 | } | 132 | } |
139 | 133 | ||
140 | /* interface towards the generic i2c driver */ | 134 | /* interface towards the generic i2c driver */ |
141 | static const struct i2c_interface fm_i2c_interface = { | 135 | static const struct i2c_interface fm_i2c_interface = { |
142 | .scl_hi = fm_scl_hi, | 136 | .scl_out = fm_scl_out, |
143 | .scl_lo = fm_scl_lo, | 137 | .scl_dir = fm_scl_dir, |
144 | .sda_hi = fm_sda_hi, | 138 | .sda_out = fm_sda_out, |
145 | .sda_lo = fm_sda_lo, | 139 | .sda_dir = fm_sda_dir, |
146 | .sda_input = fm_sda_input, | 140 | .sda_in = fm_sda_in, |
147 | .sda_output = fm_sda_output, | 141 | .scl_in = fm_scl_in, |
148 | .scl_input = fm_scl_input, | 142 | .delay = fm_delay, |
149 | .scl_output = fm_scl_output, | 143 | |
150 | .scl = fm_scl, | 144 | .delay_hd_sta = 1, |
151 | .sda = fm_sda, | 145 | .delay_hd_dat = 0, |
152 | 146 | .delay_su_dat = 1, | |
153 | .delay_hd_sta = fm_delay, | 147 | .delay_su_sto = 1, |
154 | .delay_hd_dat = fm_delay, | 148 | .delay_su_sta = 1, |
155 | .delay_su_dat = fm_delay, | 149 | .delay_thigh = 2 |
156 | .delay_su_sto = fm_delay, | ||
157 | .delay_su_sta = fm_delay, | ||
158 | .delay_thigh = fm_delay | ||
159 | }; | 150 | }; |
160 | 151 | ||
161 | /* initialise i2c for fmradio */ | 152 | /* initialise i2c for fmradio */ |