diff options
author | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-25 23:54:24 +0200 |
---|---|---|
committer | Cástor Muñoz <cmvidal@gmail.com> | 2016-05-26 09:06:30 +0200 |
commit | 9e284c11b11a09adae8073a3347480c1d580e0cc (patch) | |
tree | fa428a9a4de8be0042678d869bbd1e5cf18f1ef6 | |
parent | 2d850b7c660aa05433620083660c3b1f5f0b2592 (diff) | |
download | rockbox-9e284c11b11a09adae8073a3347480c1d580e0cc.tar.gz rockbox-9e284c11b11a09adae8073a3347480c1d580e0cc.zip |
iPod Classic: i2c updates
Change-Id: Ib516f3f52cf619fb44dc1bb6982b635c49f53a8f
-rw-r--r-- | firmware/export/s5l8702.h | 10 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/debug-s5l8702.c | 3 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/i2c-s5l8702.c | 56 |
3 files changed, 49 insertions, 20 deletions
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h index 59170b04ea..6500f69d37 100644 --- a/firmware/export/s5l8702.h +++ b/firmware/export/s5l8702.h | |||
@@ -750,18 +750,20 @@ | |||
750 | /////INTERRUPTS///// | 750 | /////INTERRUPTS///// |
751 | #define IRQ_TIMER32 7 | 751 | #define IRQ_TIMER32 7 |
752 | #define IRQ_TIMER 8 | 752 | #define IRQ_TIMER 8 |
753 | #define IRQ_SPI(i) (9+i) /* TBC */ | 753 | #define IRQ_SPI(i) (9+(i)) /* TBC */ |
754 | #define IRQ_SPI0 9 | 754 | #define IRQ_SPI0 9 |
755 | #define IRQ_SPI1 10 | 755 | #define IRQ_SPI1 10 |
756 | #define IRQ_SPI2 11 | 756 | #define IRQ_SPI2 11 |
757 | #define IRQ_LCD 14 | 757 | #define IRQ_LCD 14 |
758 | #define IRQ_DMAC(d) (16+d) | 758 | #define IRQ_DMAC(d) (16+(d)) |
759 | #define IRQ_DMAC0 16 | 759 | #define IRQ_DMAC0 16 |
760 | #define IRQ_DMAC1 17 | 760 | #define IRQ_DMAC1 17 |
761 | #define IRQ_USB_FUNC 19 | 761 | #define IRQ_USB_FUNC 19 |
762 | #define IRQ_I2C 21 /* TBC */ | 762 | #define IRQ_I2C(i) (21+(i)) |
763 | #define IRQ_I2C0 21 | ||
764 | #define IRQ_I2C1 22 | ||
763 | #define IRQ_WHEEL 23 | 765 | #define IRQ_WHEEL 23 |
764 | #define IRQ_UART(i) (24+i) | 766 | #define IRQ_UART(i) (24+(i)) |
765 | #define IRQ_UART0 24 | 767 | #define IRQ_UART0 24 |
766 | #define IRQ_UART1 25 | 768 | #define IRQ_UART1 25 |
767 | #define IRQ_UART2 26 | 769 | #define IRQ_UART2 26 |
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index cead1b7219..3faf9dfc99 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c | |||
@@ -133,6 +133,9 @@ bool dbg_hw_info(void) | |||
133 | _DEBUG_PRINTF("accessory present: %s", | 133 | _DEBUG_PRINTF("accessory present: %s", |
134 | pmu_accessory_present() ? "true" : "false"); | 134 | pmu_accessory_present() ? "true" : "false"); |
135 | #endif | 135 | #endif |
136 | extern unsigned long i2c_rd_err, i2c_wr_err; | ||
137 | line++; | ||
138 | _DEBUG_PRINTF("i2c rd/wr errors:: %lu/%lu", i2c_rd_err, i2c_wr_err); | ||
136 | } | 139 | } |
137 | #ifdef UC870X_DEBUG | 140 | #ifdef UC870X_DEBUG |
138 | else if(state==2) | 141 | else if(state==2) |
diff --git a/firmware/target/arm/s5l8702/i2c-s5l8702.c b/firmware/target/arm/s5l8702/i2c-s5l8702.c index d76bbe6c06..a795c9f18c 100644 --- a/firmware/target/arm/s5l8702/i2c-s5l8702.c +++ b/firmware/target/arm/s5l8702/i2c-s5l8702.c | |||
@@ -26,18 +26,41 @@ | |||
26 | #include "clocking-s5l8702.h" | 26 | #include "clocking-s5l8702.h" |
27 | 27 | ||
28 | /* Driver for the s5l8700 built-in I2C controller in master mode | 28 | /* Driver for the s5l8700 built-in I2C controller in master mode |
29 | 29 | ||
30 | Both the i2c_read and i2c_write function take the following arguments: | 30 | Both the i2c_read and i2c_write function take the following arguments: |
31 | * slave, the address of the i2c slave device to read from / write to | 31 | * slave, the address of the i2c slave device to read from / write to |
32 | * address, optional sub-address in the i2c slave (unused if -1) | 32 | * address, optional sub-address in the i2c slave (unused if -1) |
33 | * len, number of bytes to be transfered | 33 | * len, number of bytes to be transfered |
34 | * data, pointer to data to be transfered | 34 | * data, pointer to data to be transfered |
35 | A return value < 0 indicates an error. | 35 | A return value < 0 indicates an error. |
36 | 36 | ||
37 | Note: | 37 | Note: |
38 | * blocks the calling thread for the entire duraton of the i2c transfer but | 38 | * blocks the calling thread for the entire duraton of the i2c transfer but |
39 | uses wakeup_wait/wakeup_signal to allow other threads to run. | 39 | uses wakeup_wait/wakeup_signal to allow other threads to run. |
40 | * ACK from slave is not checked, so functions never return an error | 40 | * ACK from slave is not checked, so functions never return an error |
41 | |||
42 | Fixme: | ||
43 | * actually there is no STOP + i2c_off() on error | ||
44 | * very rare random errors when reading and/or(?) writing registers on some | ||
45 | builds/devices, hard to trace, not a 'delay' issue, it seems related | ||
46 | with alignment of STRs and/or(?) LDRs, code cache lines, pipelines... | ||
47 | The new code tries to mix STRs and LDRs at some points but ATM it is | ||
48 | unknown if it might solve or mitigate the problem. Probably it could be | ||
49 | really fixed using wait_rdy() before accessing any register, as OF does. | ||
50 | */ | ||
51 | |||
52 | /* s5l8702 I2C controller is similar to s5l8700, known differences are: | ||
53 | |||
54 | * IICCON[5] is not used in s5l8702. | ||
55 | * IICCON[13:8] are used to enable interrupts. | ||
56 | IICUNK20[13:8] are used to read the status and write-clear interrupts. | ||
57 | Known interrupts: | ||
58 | [13] STOP on bus (TBC) | ||
59 | [12] START on bus (TBC) | ||
60 | [8] byte transmited or received in Master mode (not tested in Slave) | ||
61 | * IICCON[4] does not clear interrupts, it is enabled when a byte is | ||
62 | transmited or received, in Master mode the tx/rx of the next byte | ||
63 | starts when it is written as "1". | ||
41 | */ | 64 | */ |
42 | 65 | ||
43 | static struct mutex i2c_mtx[2]; | 66 | static struct mutex i2c_mtx[2]; |
@@ -45,12 +68,11 @@ static struct mutex i2c_mtx[2]; | |||
45 | static void i2c_on(int bus) | 68 | static void i2c_on(int bus) |
46 | { | 69 | { |
47 | /* enable I2C clock */ | 70 | /* enable I2C clock */ |
48 | PWRCON(1) &= ~(1 << 4); | 71 | clockgate_enable(I2CCLKGATE(bus), true); |
49 | 72 | ||
50 | IICCON(bus) = (1 << 7) | /* ACK_GEN */ | 73 | IICCON(bus) = (0 << 8) | /* INT_EN = disabled */ |
74 | (1 << 7) | /* ACK_GEN */ | ||
51 | (0 << 6) | /* CLKSEL = PCLK/16 */ | 75 | (0 << 6) | /* CLKSEL = PCLK/16 */ |
52 | (1 << 5) | /* INT_EN */ | ||
53 | (1 << 4) | /* IRQ clear */ | ||
54 | (7 << 0); /* CK_REG */ | 76 | (7 << 0); /* CK_REG */ |
55 | 77 | ||
56 | /* serial output on */ | 78 | /* serial output on */ |
@@ -63,7 +85,7 @@ static void i2c_off(int bus) | |||
63 | IICSTAT(bus) = 0; | 85 | IICSTAT(bus) = 0; |
64 | 86 | ||
65 | /* disable I2C clock */ | 87 | /* disable I2C clock */ |
66 | PWRCON(1) |= (1 << 4); | 88 | clockgate_enable(I2CCLKGATE(bus), false); |
67 | } | 89 | } |
68 | 90 | ||
69 | void i2c_init() | 91 | void i2c_init() |
@@ -80,7 +102,6 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch | |||
80 | /* START */ | 102 | /* START */ |
81 | IICDS(bus) = slave & ~1; | 103 | IICDS(bus) = slave & ~1; |
82 | IICSTAT(bus) = 0xF0; | 104 | IICSTAT(bus) = 0xF0; |
83 | IICCON(bus) = 0xB3; | ||
84 | while ((IICCON(bus) & 0x10) == 0) | 105 | while ((IICCON(bus) & 0x10) == 0) |
85 | if (TIME_AFTER(USEC_TIMER, timeout)) | 106 | if (TIME_AFTER(USEC_TIMER, timeout)) |
86 | return 1; | 107 | return 1; |
@@ -88,7 +109,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch | |||
88 | if (address >= 0) { | 109 | if (address >= 0) { |
89 | /* write address */ | 110 | /* write address */ |
90 | IICDS(bus) = address; | 111 | IICDS(bus) = address; |
91 | IICCON(bus) = 0xB3; | 112 | IICCON(bus) = IICCON(bus); |
92 | while ((IICCON(bus) & 0x10) == 0) | 113 | while ((IICCON(bus) & 0x10) == 0) |
93 | if (TIME_AFTER(USEC_TIMER, timeout)) | 114 | if (TIME_AFTER(USEC_TIMER, timeout)) |
94 | return 2; | 115 | return 2; |
@@ -97,7 +118,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch | |||
97 | /* write data */ | 118 | /* write data */ |
98 | while (len--) { | 119 | while (len--) { |
99 | IICDS(bus) = *data++; | 120 | IICDS(bus) = *data++; |
100 | IICCON(bus) = 0xB3; | 121 | IICCON(bus) = IICCON(bus); |
101 | while ((IICCON(bus) & 0x10) == 0) | 122 | while ((IICCON(bus) & 0x10) == 0) |
102 | if (TIME_AFTER(USEC_TIMER, timeout)) | 123 | if (TIME_AFTER(USEC_TIMER, timeout)) |
103 | return 4; | 124 | return 4; |
@@ -105,7 +126,7 @@ int i2c_wr(int bus, unsigned char slave, int address, int len, const unsigned ch | |||
105 | 126 | ||
106 | /* STOP */ | 127 | /* STOP */ |
107 | IICSTAT(bus) = 0xD0; | 128 | IICSTAT(bus) = 0xD0; |
108 | IICCON(bus) = 0xB3; | 129 | IICCON(bus) = IICCON(bus); |
109 | while ((IICSTAT(bus) & (1 << 5)) != 0) | 130 | while ((IICSTAT(bus) & (1 << 5)) != 0) |
110 | if (TIME_AFTER(USEC_TIMER, timeout)) | 131 | if (TIME_AFTER(USEC_TIMER, timeout)) |
111 | return 5; | 132 | return 5; |
@@ -123,14 +144,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da | |||
123 | /* START */ | 144 | /* START */ |
124 | IICDS(bus) = slave & ~1; | 145 | IICDS(bus) = slave & ~1; |
125 | IICSTAT(bus) = 0xF0; | 146 | IICSTAT(bus) = 0xF0; |
126 | IICCON(bus) = 0xB3; | ||
127 | while ((IICCON(bus) & 0x10) == 0) | 147 | while ((IICCON(bus) & 0x10) == 0) |
128 | if (TIME_AFTER(USEC_TIMER, timeout)) | 148 | if (TIME_AFTER(USEC_TIMER, timeout)) |
129 | return 1; | 149 | return 1; |
130 | 150 | ||
131 | /* write address */ | 151 | /* write address */ |
132 | IICDS(bus) = address; | 152 | IICDS(bus) = address; |
133 | IICCON(bus) = 0xB3; | 153 | IICCON(bus) = IICCON(bus); |
134 | while ((IICCON(bus) & 0x10) == 0) | 154 | while ((IICCON(bus) & 0x10) == 0) |
135 | if (TIME_AFTER(USEC_TIMER, timeout)) | 155 | if (TIME_AFTER(USEC_TIMER, timeout)) |
136 | return 2; | 156 | return 2; |
@@ -139,13 +159,13 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da | |||
139 | /* (repeated) START */ | 159 | /* (repeated) START */ |
140 | IICDS(bus) = slave | 1; | 160 | IICDS(bus) = slave | 1; |
141 | IICSTAT(bus) = 0xB0; | 161 | IICSTAT(bus) = 0xB0; |
142 | IICCON(bus) = 0xB3; | 162 | IICCON(bus) = IICCON(bus); |
143 | while ((IICCON(bus) & 0x10) == 0) | 163 | while ((IICCON(bus) & 0x10) == 0) |
144 | if (TIME_AFTER(USEC_TIMER, timeout)) | 164 | if (TIME_AFTER(USEC_TIMER, timeout)) |
145 | return 3; | 165 | return 3; |
146 | 166 | ||
147 | while (len--) { | 167 | while (len--) { |
148 | IICCON(bus) = (len == 0) ? 0x33 : 0xB3; /* NAK or ACK */ | 168 | IICCON(bus) &= ~(len ? 0 : 0x80); /* ACK or NAK */ |
149 | while ((IICCON(bus) & 0x10) == 0) | 169 | while ((IICCON(bus) & 0x10) == 0) |
150 | if (TIME_AFTER(USEC_TIMER, timeout)) | 170 | if (TIME_AFTER(USEC_TIMER, timeout)) |
151 | return 4; | 171 | return 4; |
@@ -154,7 +174,7 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da | |||
154 | 174 | ||
155 | /* STOP */ | 175 | /* STOP */ |
156 | IICSTAT(bus) = 0x90; | 176 | IICSTAT(bus) = 0x90; |
157 | IICCON(bus) = 0xB3; | 177 | IICCON(bus) = IICCON(bus); |
158 | while ((IICSTAT(bus) & (1 << 5)) != 0) | 178 | while ((IICSTAT(bus) & (1 << 5)) != 0) |
159 | if (TIME_AFTER(USEC_TIMER, timeout)) | 179 | if (TIME_AFTER(USEC_TIMER, timeout)) |
160 | return 5; | 180 | return 5; |
@@ -163,12 +183,15 @@ int i2c_rd(int bus, unsigned char slave, int address, int len, unsigned char *da | |||
163 | return 0; | 183 | return 0; |
164 | } | 184 | } |
165 | 185 | ||
186 | unsigned long i2c_rd_err, i2c_wr_err; | ||
187 | |||
166 | int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data) | 188 | int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data) |
167 | { | 189 | { |
168 | int ret; | 190 | int ret; |
169 | mutex_lock(&i2c_mtx[bus]); | 191 | mutex_lock(&i2c_mtx[bus]); |
170 | ret = i2c_wr(bus, slave, address, len, data); | 192 | ret = i2c_wr(bus, slave, address, len, data); |
171 | mutex_unlock(&i2c_mtx[bus]); | 193 | mutex_unlock(&i2c_mtx[bus]); |
194 | if (ret) i2c_wr_err++; | ||
172 | return ret; | 195 | return ret; |
173 | } | 196 | } |
174 | 197 | ||
@@ -178,6 +201,7 @@ int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char * | |||
178 | mutex_lock(&i2c_mtx[bus]); | 201 | mutex_lock(&i2c_mtx[bus]); |
179 | ret = i2c_rd(bus, slave, address, len, data); | 202 | ret = i2c_rd(bus, slave, address, len, data); |
180 | mutex_unlock(&i2c_mtx[bus]); | 203 | mutex_unlock(&i2c_mtx[bus]); |
204 | if (ret) i2c_rd_err++; | ||
181 | return ret; | 205 | return ret; |
182 | } | 206 | } |
183 | 207 | ||