Date: | 2011-06-25 21:50:38 (12 years 9 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | 1fe9fab97a0223d02fd74390b3a89d5f0f14ee37 |
Message: | spi_atben: added optimized unidirectional SPI bitbangers The optimized bitbangers save the accesses for the unused direction. Also, the tx bitbanger tries to minimize PDDATS/PDDATC writes that only change MOSI. |
Files: |
drivers/spi/spi_atben.c (2 diffs) |
Change Details
drivers/spi/spi_atben.c | ||
---|---|---|
78 | 78 | /* ----- SPI transfers ----------------------------------------------------- */ |
79 | 79 | |
80 | 80 | |
81 | static void rx_only(const struct atben_prv *prv, uint8_t *buf, int len) | |
82 | { | |
83 | uint8_t v; | |
84 | ||
85 | while (len--) { | |
86 | writel(SCLK, PDDATS); | |
87 | v = readl(PDPIN) & MISO ? 0x80 : 0; | |
88 | writel(SCLK, PDDATC); | |
89 | ||
90 | #define DO_BIT(m) \ | |
91 | writel(SCLK, PDDATS); \ | |
92 | if (readl(PDPIN) & MISO) \ | |
93 | v |= (m); \ | |
94 | writel(SCLK, PDDATC) | |
95 | ||
96 | DO_BIT(0x40); | |
97 | DO_BIT(0x20); | |
98 | DO_BIT(0x10); | |
99 | DO_BIT(0x08); | |
100 | DO_BIT(0x04); | |
101 | DO_BIT(0x02); | |
102 | DO_BIT(0x01); | |
103 | ||
104 | #undef DO_BIT | |
105 | ||
106 | *buf++ = v; | |
107 | } | |
108 | } | |
109 | ||
110 | ||
111 | static void tx_only(const struct atben_prv *prv, const uint8_t *buf, int len) | |
112 | { | |
113 | uint8_t tv; | |
114 | ||
115 | while (len--) { | |
116 | tv = *buf++; | |
117 | ||
118 | if (tv & 0x80) { | |
119 | writel(MOSI, PDDATS); | |
120 | goto b6_1; | |
121 | } else { | |
122 | writel(MOSI, PDDATC); | |
123 | goto b6_0; | |
124 | } | |
125 | ||
126 | #define DO_BIT(m, this, next) \ | |
127 | this##_1: \ | |
128 | writel(SCLK, PDDATS); \ | |
129 | if (tv & (m)) { \ | |
130 | writel(SCLK, PDDATC); \ | |
131 | goto next##_1; \ | |
132 | } else { \ | |
133 | writel(MOSI | SCLK, PDDATC); \ | |
134 | goto next##_0; \ | |
135 | } \ | |
136 | this##_0: \ | |
137 | writel(SCLK, PDDATS); \ | |
138 | writel(SCLK, PDDATC); \ | |
139 | if (tv & (m)) { \ | |
140 | writel(MOSI, PDDATS); \ | |
141 | goto next##_1; \ | |
142 | } else { \ | |
143 | goto next##_0; \ | |
144 | } | |
145 | ||
146 | DO_BIT(0x40, b6, b5); | |
147 | DO_BIT(0x20, b5, b4); | |
148 | DO_BIT(0x10, b4, b3); | |
149 | DO_BIT(0x08, b3, b2); | |
150 | DO_BIT(0x04, b2, b1); | |
151 | DO_BIT(0x02, b1, b0); | |
152 | DO_BIT(0x01, b0, done); | |
153 | ||
154 | #undef DO_BIT | |
155 | ||
156 | done_1: | |
157 | done_0: | |
158 | writel(SCLK, PDDATS); | |
159 | writel(SCLK, PDDATC); | |
160 | writel(SCLK, PDDATC); /* delay to meet t5 timing */ | |
161 | } | |
162 | } | |
163 | ||
164 | ||
165 | static void bidir(const struct atben_prv *prv, const uint8_t *tx, uint8_t *rx, | |
166 | int len) | |
167 | { | |
168 | uint8_t mask, tv, rv; | |
169 | ||
170 | while (len--) { | |
171 | tv = *tx++; | |
172 | for (mask = 0x80; mask; mask >>= 1) { | |
173 | if (tv & mask) | |
174 | writel(MOSI, PDDATS); | |
175 | else | |
176 | writel(MOSI, PDDATC); | |
177 | writel(SCLK, PDDATS); | |
178 | if (readl(PDPIN) & MISO) | |
179 | rv |= mask; | |
180 | writel(SCLK, PDDATC); | |
181 | } | |
182 | *rx++ = rv; | |
183 | } | |
184 | } | |
185 | ||
186 | ||
81 | 187 | static int atben_transfer(struct spi_device *spi, struct spi_message *msg) |
82 | 188 | { |
83 | 189 | struct atben_prv *prv = spi_master_get_devdata(spi->master); |
84 | 190 | struct spi_transfer *xfer; |
85 | 191 | struct spi_transfer *x[2]; |
86 | int n, i; | |
192 | int n; | |
87 | 193 | |
88 | 194 | if (unlikely(list_empty(&msg->transfers))) { |
89 | 195 | dev_err(prv->dev, "transfer is empty\n"); |
... | ... | |
131 | 237 | |
132 | 238 | tx = xfer->tx_buf; |
133 | 239 | rx = xfer->rx_buf; |
134 | for (i = 0; i != xfer->len; i++) { | |
135 | uint8_t mask, tv = 0, rv = 0; | |
136 | ||
137 | if (tx) | |
138 | tv = *tx++; | |
139 | for (mask = 0x80; mask; mask >>= 1) { | |
140 | if (tv & mask) | |
141 | writel(MOSI, PDDATS); | |
142 | else | |
143 | writel(MOSI, PDDATC); | |
144 | writel(SCLK, PDDATS); | |
145 | if (readl(PDPIN) & MISO) | |
146 | rv |= mask; | |
147 | writel(SCLK, PDDATC); | |
148 | } | |
149 | if (rx) | |
150 | *rx++ = rv; | |
151 | } | |
240 | if (!tx) | |
241 | rx_only(prv, rx, xfer->len); | |
242 | else if (!rx) | |
243 | tx_only(prv, tx, xfer->len); | |
244 | else | |
245 | bidir(prv, tx, rx, xfer->len); | |
152 | 246 | } |
153 | 247 | writel(nSEL, PDDATS); |
154 | 248 |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9