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
7878/* ----- SPI transfers ----------------------------------------------------- */
7979
8080
81static 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
111static 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
156done_1:
157done_0:
158        writel(SCLK, PDDATS);
159        writel(SCLK, PDDATC);
160        writel(SCLK, PDDATC); /* delay to meet t5 timing */
161    }
162}
163
164
165static 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
81187static int atben_transfer(struct spi_device *spi, struct spi_message *msg)
82188{
83189    struct atben_prv *prv = spi_master_get_devdata(spi->master);
84190    struct spi_transfer *xfer;
85191    struct spi_transfer *x[2];
86    int n, i;
192    int n;
87193
88194     if (unlikely(list_empty(&msg->transfers))) {
89195        dev_err(prv->dev, "transfer is empty\n");
...... 
131237
132238        tx = xfer->tx_buf;
133239        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);
152246    }
153247    writel(nSEL, PDDATS);
154248

Archive Download the corresponding diff file



interactive