summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-05-25 23:54:24 +0200
committerCástor Muñoz <cmvidal@gmail.com>2016-05-26 09:06:30 +0200
commit9e284c11b11a09adae8073a3347480c1d580e0cc (patch)
treefa428a9a4de8be0042678d869bbd1e5cf18f1ef6
parent2d850b7c660aa05433620083660c3b1f5f0b2592 (diff)
downloadrockbox-9e284c11b11a09adae8073a3347480c1d580e0cc.tar.gz
rockbox-9e284c11b11a09adae8073a3347480c1d580e0cc.zip
iPod Classic: i2c updates
Change-Id: Ib516f3f52cf619fb44dc1bb6982b635c49f53a8f
-rw-r--r--firmware/export/s5l8702.h10
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c3
-rw-r--r--firmware/target/arm/s5l8702/i2c-s5l8702.c56
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
43static struct mutex i2c_mtx[2]; 66static struct mutex i2c_mtx[2];
@@ -45,12 +68,11 @@ static struct mutex i2c_mtx[2];
45static void i2c_on(int bus) 68static 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
69void i2c_init() 91void 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
186unsigned long i2c_rd_err, i2c_wr_err;
187
166int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data) 188int 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