From 0d3f076b5fbe4d901373000033e821e40bd3c901 Mon Sep 17 00:00:00 2001 From: Bart Van Der Meerssche Date: Wed, 19 Jan 2011 22:12:49 +0100 Subject: [PATCH] [spidev + nixio + fluksod] allow the bitbanged spi max speed and inter-byte delay to be dynamically set from user space --- .../package/flukso/luasrc/flukso/spi.lua | 88 ++++--- .../openwrt/package/flukso/luasrc/fluksod.lua | 2 +- .../openwrt/package/luci/libs/nixio/Makefile | 2 +- .../package/luci/libs/nixio/src/file.c | 65 +---- .../package/luci/libs/nixio/src/nixio.c | 1 + .../package/luci/libs/nixio/src/nixio.h | 1 + .../openwrt/package/luci/libs/nixio/src/spi.c | 89 +++++++ .../patches/400-spi_gpio_support.patch | 2 +- .../patches/410-spi_gpio_enable_cs_line.patch | 2 +- .../420-tune_spi_bitbanging_for_avr.patch | 241 ++++++++++++++++-- 10 files changed, 366 insertions(+), 127 deletions(-) create mode 100644 mote/v2/openwrt/package/luci/libs/nixio/src/spi.c diff --git a/mote/v2/openwrt/package/flukso/luasrc/flukso/spi.lua b/mote/v2/openwrt/package/flukso/luasrc/flukso/spi.lua index e28444c..a27bcea 100644 --- a/mote/v2/openwrt/package/flukso/luasrc/flukso/spi.lua +++ b/mote/v2/openwrt/package/flukso/luasrc/flukso/spi.lua @@ -37,10 +37,10 @@ local SPI_MAX_READ_BYTES = 256 -- Attributes: -- { to = ctrl | delta | uart -- body = --- parsed = { , , , ... } +-- parsed = { 'cmd' = , 1 = , 2 = , ... } -- encoded = -- received = { raw = , l = , crc = , u = } --- decoded = { l = ..., u = ... } +-- decoded = { args = , cmd = , 1 = , 2= , ..., u = } -- reply = -- } -- @@ -54,7 +54,7 @@ end function parse(msg) msg.parsed = {} - msg.parsed[1] = msg.body:match('^%l%l') + msg.parsed.cmd = msg.body:match('^%l%l') for arg in msg.body:gmatch('%d+') do msg.parsed[#msg.parsed + 1] = arg end @@ -68,33 +68,33 @@ function encode(msg) return end - if msg.parsed[1] == 'gd' then - msg.encoded = msg.parsed[1] - elseif msg.parsed[1] == 'gv' then + if msg.parsed.cmd == 'gd' then + msg.encoded = msg.parsed.cmd + elseif msg.parsed.cmd == 'gv' then - elseif msg.parsed[1] == 'gp' then + elseif msg.parsed.cmd == 'gp' then - elseif msg.parsed[1] == 'gc' then + elseif msg.parsed.cmd == 'gc' then - elseif msg.parsed[1] == 'gm' then + elseif msg.parsed.cmd == 'gm' then - elseif msg.parsed[1] == 'gw' then + elseif msg.parsed.cmd == 'gw' then - elseif msg.parsed[1] == 'gb' then + elseif msg.parsed.cmd == 'gb' then - elseif msg.parsed[1] == 'sv' then + elseif msg.parsed.cmd == 'sv' then - elseif msg.parsed[1] == 'sp' then + elseif msg.parsed.cmd == 'sp' then - elseif msg.parsed[1] == 'sc' then + elseif msg.parsed.cmd == 'sc' then - elseif msg.parsed[1] == 'sm' then + elseif msg.parsed.cmd == 'sm' then - elseif msg.parsed[1] == 'sw' then + elseif msg.parsed.cmd == 'sw' then - elseif msg.parsed[1] == 'sb' then + elseif msg.parsed.cmd == 'sb' then - elseif msg.parsed[1] == 'ct' then + elseif msg.parsed.cmd == 'ct' then else @@ -116,15 +116,20 @@ function rx(msg, cdev) msg.received.raw = cdev:read(SPI_MAX_READ_BYTES) msg.received.l, msg.received.u = msg.received.raw:match('^l(%w*)%.?u(%w*)%.?$') -- protect against nil values when match should fail + -- TODO error handling when no reply due to: + -- * sensor board not operational + -- * state machine not synced msg.received.l, msg.received.u = msg.received.l or '', msg.received.u or '' - if msg.received.l ~= '' and msg.received.l:sub(1, 2) == msg.parsed[1] then + if msg.received.l ~= '' then msg.received.crc = msg.received.l:sub(-2, -1) - msg.received.l = msg.received.l:sub(1, -3) + msg.received.l = msg.received.l:sub( 1, -3) if nixio.bin.dow_crc(msg.received.l) ~= nixio.bin.hextonum(msg.received.crc) then - --> TODO implement crc error counter + --> TODO implement near-end crc error counter msg.received.l = '' + else + end end end @@ -137,43 +142,46 @@ function decode(msg) end if msg.received.l ~= '' then - msg.decoded.largs = msg.received.l:sub(3, -1) + msg.decoded.cmd = msg.received.l:sub(1, 2) + msg.decoded.args = msg.received.l:sub(3, -1) - if msg.parsed[1] == 'gd' then - for i = 1, msg.decoded.largs:len() / 18 do + if msg.decoded.cmd == 'gd' then + for i = 1, msg.decoded.args:len() / 18 do msg.decoded[(i-1)*3 + 1] = - nixio.bin.hextonum(msg.decoded.largs:sub((i-1)*18 + 1, (i-1)*18 + 2)) + nixio.bin.hextonum(msg.decoded.args:sub((i-1)*18 + 1, (i-1)*18 + 2)) msg.decoded[(i-1)*3 + 2] = - nixio.bin.hextonum(msg.decoded.largs:sub((i-1)*18 + 3, (i-1)*18 + 10)) + nixio.bin.hextonum(msg.decoded.args:sub((i-1)*18 + 3, (i-1)*18 + 10)) msg.decoded[(i-1)*3 + 3] = - nixio.bin.hextonum(msg.decoded.largs:sub((i-1)*18 + 11, (i-1)*18 + 18)) + nixio.bin.hextonum(msg.decoded.args:sub((i-1)*18 + 11, (i-1)*18 + 18)) end - elseif msg.parsed[1] == 'gv' then + elseif msg.parsed.cmd == 'gv' then - elseif msg.parsed[1] == 'gp' then + elseif msg.parsed.cmd == 'gp' then - elseif msg.parsed[1] == 'gc' then + elseif msg.parsed.cmd == 'gc' then - elseif msg.parsed[1] == 'gm' then + elseif msg.parsed.cmd == 'gm' then - elseif msg.parsed[1] == 'gw' then + elseif msg.parsed.cmd == 'gw' then - elseif msg.parsed[1] == 'gb' then + elseif msg.parsed.cmd == 'gb' then - elseif msg.parsed[1] == 'sv' then + elseif msg.parsed.cmd == 'sv' then - elseif msg.parsed[1] == 'sp' then + elseif msg.parsed.cmd == 'sp' then - elseif msg.parsed[1] == 'sc' then + elseif msg.parsed.cmd == 'sc' then - elseif msg.parsed[1] == 'sm' then + elseif msg.parsed.cmd == 'sm' then - elseif msg.parsed[1] == 'sw' then + elseif msg.parsed.cmd == 'sw' then - elseif msg.parsed[1] == 'sb' then + elseif msg.parsed.cmd == 'sb' then - elseif msg.parsed[1] == 'ct' then + elseif msg.parsed.cmd == 'ct' then + elseif msg.decoded.cmd == 'zz' then + --> TODO implement far-end crc error counter end end end diff --git a/mote/v2/openwrt/package/flukso/luasrc/fluksod.lua b/mote/v2/openwrt/package/flukso/luasrc/fluksod.lua index c81fb46..cbfa1e3 100755 --- a/mote/v2/openwrt/package/flukso/luasrc/fluksod.lua +++ b/mote/v2/openwrt/package/flukso/luasrc/fluksod.lua @@ -72,7 +72,7 @@ while true do msg:rx(spidev) msg:decode() --> dbg.vardump(msg) - delta.fdout:write(msg.parsed[1] .. ' ' .. table.concat(msg.decoded, ' ') .. '\n') + delta.fdout:write(msg.decoded.cmd .. ' ' .. table.concat(msg.decoded, ' ') .. '\n') end end end diff --git a/mote/v2/openwrt/package/luci/libs/nixio/Makefile b/mote/v2/openwrt/package/luci/libs/nixio/Makefile index a8a57b3..126b9a5 100644 --- a/mote/v2/openwrt/package/luci/libs/nixio/Makefile +++ b/mote/v2/openwrt/package/luci/libs/nixio/Makefile @@ -15,7 +15,7 @@ NIXIO_SO = nixio.so NIXIO_OBJ = src/nixio.o src/socket.o src/sockopt.o src/bind.o src/address.o \ src/poll.o src/io.o src/file.o src/splice.o src/process.o src/syslog.o \ - src/bit.o src/binary.o src/fs.o src/user.o \ + src/bit.o src/binary.o src/fs.o src/user.o src/spi.o \ $(if $(NIXIO_TLS),src/tls-crypto.o src/tls-context.o src/tls-socket.o,) ifeq ($(NIXIO_TLS),axtls) diff --git a/mote/v2/openwrt/package/luci/libs/nixio/src/file.c b/mote/v2/openwrt/package/luci/libs/nixio/src/file.c index 67c88b7..b86e040 100644 --- a/mote/v2/openwrt/package/luci/libs/nixio/src/file.c +++ b/mote/v2/openwrt/package/luci/libs/nixio/src/file.c @@ -223,68 +223,6 @@ static int nixio_file_read(lua_State *L) { } } -static int nixio_file_spi_read(lua_State *L) { - int fd = nixio__checkfd(L, 1); - char buffer[NIXIO_BUFFERSIZE]; - int readc; - size_t len; - char last = 0; - - for (size_t i = 0; i < NIXIO_BUFFERSIZE; i++) { - do { - readc = read(fd, buffer + i, 1); - } while (readc == -1 && errno == EINTR); - - if (readc < 0) { - return nixio__perror(L); - } - - if (last) { - break; - } - - if (buffer[i] == 0x00) { - len = i; - last = 1; /* one last pass through the for loop to sync the state machine */ - - } - } - -/* REVISIT: a read on spidev doens't work for numbytes > 1 */ - -/* for (size_t i = 0; i < NIXIO_BUFFERSIZE; i += 2) { - do { - readc = read(fd, buffer + i, 2); - } while (readc == -1 && errno == EINTR); - - if (readc < 0) { - return nixio__perror(L); - } - - if (buffer[i + 1] == 0x00) { - len = i; - - if (buffer[i] != 0x00) { - len = i + 1; - - do { - readc = read(fd, buffer + i + 2, 1); - } while (readc == -1 && errno == EINTR); - - if (readc < 0) { - return nixio__perror(L); - } - } - - break; - } - - } -*/ - - lua_pushlstring(L, buffer, len); - return 1; -} static int nixio_file_seek(lua_State *L) { int fd = nixio__checkfd(L, 1); @@ -412,7 +350,6 @@ static int nixio_file__tostring(lua_State *L) { static const luaL_reg M[] = { {"write", nixio_file_write}, {"read", nixio_file_read}, - {"spiread", nixio_file_spi_read}, {"tell", nixio_file_tell}, {"seek", nixio_file_seek}, {"stat", nixio_file_stat}, @@ -428,7 +365,7 @@ static const luaL_reg M[] = { static const luaL_reg R[] = { {"dup", nixio_dup}, {"open", nixio_open}, - {"open_flags", nixio_open_flags}, + {"open_flags", nixio_open_flags}, {"pipe", nixio_pipe}, {NULL, NULL} }; diff --git a/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.c b/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.c index f6e8e18..3e98b27 100644 --- a/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.c +++ b/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.c @@ -142,6 +142,7 @@ NIXIO_API int luaopen_nixio(lua_State *L) { nixio_open_bin(L); nixio_open_fs(L); nixio_open_user(L); + nixio_open_spi(L); #ifndef NO_TLS nixio_open_tls_crypto(L); diff --git a/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.h b/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.h index 2be197f..749f4d3 100644 --- a/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.h +++ b/mote/v2/openwrt/package/luci/libs/nixio/src/nixio.h @@ -120,6 +120,7 @@ void nixio_open_bit(lua_State *L); void nixio_open_bin(lua_State *L); void nixio_open_fs(lua_State *L); void nixio_open_user(lua_State *L); +void nixio_open_spi(lua_State *L); #ifndef NO_TLS void nixio_open_tls_crypto(lua_State *L); diff --git a/mote/v2/openwrt/package/luci/libs/nixio/src/spi.c b/mote/v2/openwrt/package/luci/libs/nixio/src/spi.c new file mode 100644 index 0000000..3563824 --- /dev/null +++ b/mote/v2/openwrt/package/luci/libs/nixio/src/spi.c @@ -0,0 +1,89 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2011 Bart Van Der Meerssche + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include +#include +#include +#include +#include + +/* Defined in linux/spi/spidev.h, but this doesn't seem to propagate to the openwrt staging dir */ +/* Read / Write SPI device default delay us */ +#define SPI_IOC_RD_DELAY_US _IOR(SPI_IOC_MAGIC, 5, __u32) +#define SPI_IOC_WR_DELAY_US _IOW(SPI_IOC_MAGIC, 5, __u32) + + +static int nixio_spi_setspeed(lua_State *L) { + int fd = nixio__checkfd(L, 1); + ulong speed_hz = luaL_checkinteger(L, 2); + uint delay_usecs = luaL_checkinteger(L, 3); + + if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) < 0) { + return nixio__perror(L); + } else if (ioctl(fd, SPI_IOC_WR_DELAY_US, &delay_usecs) < 0) { + return nixio__perror(L); + } + + return 0; +} + +/* not really needed anymore since this is now coded into the spi_bitbang kmod */ +static int nixio_spi_read(lua_State *L) { + int fd = nixio__checkfd(L, 1); + char buffer[NIXIO_BUFFERSIZE]; + int readc; + size_t len; + char last = 0; + + for (size_t i = 0; i < NIXIO_BUFFERSIZE; i++) { + do { + readc = read(fd, buffer + i, 1); + } while (readc == -1 && errno == EINTR); + + if (readc < 0) { + return nixio__perror(L); + } + + if (last) { + break; + } + + if (buffer[i] == 0x00) { + len = i; + last = 1; /* one last pass through the for loop to sync the state machine */ + + } + } + + lua_pushlstring(L, buffer, len); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"setspeed", nixio_spi_setspeed}, + {"read", nixio_spi_read}, + {NULL, NULL} +}; + +void nixio_open_spi(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_setfield(L, -2, "spi"); +} diff --git a/mote/v2/openwrt/patches/400-spi_gpio_support.patch b/mote/v2/openwrt/patches/400-spi_gpio_support.patch index 8ac1bf9..2df4898 100644 --- a/mote/v2/openwrt/patches/400-spi_gpio_support.patch +++ b/mote/v2/openwrt/patches/400-spi_gpio_support.patch @@ -41,7 +41,7 @@ + .modalias = "spidev", + .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT, + .mode = SPI_MODE_0, -+ .max_speed_hz = 16000000, /* 16kHz */ ++ .max_speed_hz = 1000000, /* 1Mhz max, but the bitbanged spi doesn't clock faster than 572kHz */ + .bus_num = 0, +}, +}; diff --git a/mote/v2/openwrt/patches/410-spi_gpio_enable_cs_line.patch b/mote/v2/openwrt/patches/410-spi_gpio_enable_cs_line.patch index 4f84542..e619897 100644 --- a/mote/v2/openwrt/patches/410-spi_gpio_enable_cs_line.patch +++ b/mote/v2/openwrt/patches/410-spi_gpio_enable_cs_line.patch @@ -15,5 +15,5 @@ - .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT, + .controller_data = (void *) SPI_GPIO_CS, .mode = SPI_MODE_0, - .max_speed_hz = 10000000, /* 10kHz */ + .max_speed_hz = 1000000, /* 1Mhz max, but the bitbanged spi doesn't clock faster than 572kHz */ .bus_num = 0, diff --git a/mote/v2/openwrt/patches/420-tune_spi_bitbanging_for_avr.patch b/mote/v2/openwrt/patches/420-tune_spi_bitbanging_for_avr.patch index 49472fb..ffd81e4 100644 --- a/mote/v2/openwrt/patches/420-tune_spi_bitbanging_for_avr.patch +++ b/mote/v2/openwrt/patches/420-tune_spi_bitbanging_for_avr.patch @@ -1,32 +1,173 @@ ---- a/drivers/spi/spi_gpio.c 2010-12-14 01:02:26.673204002 +0100 -+++ b/drivers/spi/spi_gpio.c 2011-01-15 00:26:44.437652996 +0100 -@@ -158,7 +158,9 @@ - static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) - { -- return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); -+ /* shift out a byte in 165us, then pause for 335us */ -+ ndelay(335); -+ return bitbang_txrx_be_cpha0(spi, 5, 0, word, 8); - } +--- a/include/linux/spi/spi.h 2009-12-04 07:00:07.000000000 +0100 ++++ b/include/linux/spi/spi.h 2011-01-18 14:30:48.919450001 +0100 +@@ -68,6 +68,7 @@ + struct device dev; + struct spi_master *master; + u32 max_speed_hz; ++ u16 delay_usecs; + u8 chip_select; + u8 mode; + #define SPI_CPHA 0x01 /* clock phase */ +--- a/include/linux/spi/spidev.h 2009-12-04 07:00:07.000000000 +0100 ++++ b/include/linux/spi/spidev.h 2011-01-18 14:09:47.719449999 +0100 +@@ -124,6 +124,8 @@ + #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) + #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) - static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, +- ++/* Read / Write SPI device default delay us */ ++#define SPI_IOC_RD_DELAY_US _IOR(SPI_IOC_MAGIC, 5, __u32) ++#define SPI_IOC_WR_DELAY_US _IOW(SPI_IOC_MAGIC, 5, __u32) + + #endif /* SPIDEV_H */ +--- a/include/linux/spi/spi_bitbang.h 2009-12-04 07:00:07.000000000 +0100 ++++ b/include/linux/spi/spi_bitbang.h 2011-01-18 13:33:26.731450001 +0100 +@@ -50,7 +50,7 @@ + + /* txrx_word[SPI_MODE_*]() just looks like a shift register */ + u32 (*txrx_word[4])(struct spi_device *spi, +- unsigned nsecs, ++ unsigned bit_delay, unsigned byte_delay, + u32 word, u8 bits); + }; + +@@ -102,20 +102,22 @@ + + static inline u32 + bitbang_txrx_be_cpha0(struct spi_device *spi, +- unsigned nsecs, unsigned cpol, +- u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, ++ unsigned cpol, u32 word, u8 bits) + { + /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ + ++ spidelay(byte_delay); ++ + /* clock starts at inactive polarity */ + for (word <<= (32 - bits); likely(bits); bits--) { + + /* setup MSB (to slave) on trailing edge */ + setmosi(spi, word & (1 << 31)); +- spidelay(nsecs); /* T(setup) */ ++ spidelay(bit_delay); /* T(setup) */ + + setsck(spi, !cpol); +- spidelay(nsecs); ++ spidelay(bit_delay); + + /* sample MSB (from slave) on leading edge */ + word <<= 1; +@@ -127,21 +129,23 @@ + + static inline u32 + bitbang_txrx_be_cpha1(struct spi_device *spi, +- unsigned nsecs, unsigned cpol, +- u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, ++ unsigned cpol, u32 word, u8 bits) + { + /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ + ++ spidelay(byte_delay); ++ + /* clock starts at inactive polarity */ + for (word <<= (32 - bits); likely(bits); bits--) { + + /* setup MSB (to slave) on leading edge */ + setsck(spi, !cpol); + setmosi(spi, word & (1 << 31)); +- spidelay(nsecs); /* T(setup) */ ++ spidelay(bit_delay); /* T(setup) */ + + setsck(spi, cpol); +- spidelay(nsecs); ++ spidelay(bit_delay); + + /* sample MSB (from slave) on trailing edge */ + word <<= 1; +--- a/drivers/spi/spidev.c 2009-12-04 07:00:07.000000000 +0100 ++++ b/drivers/spi/spidev.c 2011-01-18 14:15:00.971449999 +0100 +@@ -362,6 +362,9 @@ + case SPI_IOC_RD_MAX_SPEED_HZ: + retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); + break; ++ case SPI_IOC_RD_DELAY_US: ++ retval = __put_user(spi->delay_usecs, (__u32 __user *)arg); ++ break; + + /* write requests */ + case SPI_IOC_WR_MODE: +@@ -426,7 +429,19 @@ + dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); + } + break; ++ case SPI_IOC_WR_DELAY_US: ++ retval = __get_user(tmp, (__u32 __user *)arg); ++ if (retval == 0) { ++ u32 save = spi->delay_usecs; + ++ spi->delay_usecs = tmp; ++ retval = spi_setup(spi); ++ if (retval < 0) ++ spi->delay_usecs = save; ++ else ++ dev_dbg(&spi->dev, "%d us delay\n", tmp); ++ } ++ break; + default: + /* segmented and/or full-duplex I/O request */ + if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) --- a/drivers/spi/spi_bitbang.c 2009-12-04 07:00:07.000000000 +0100 -+++ b/drivers/spi/spi_bitbang.c 2011-01-15 00:45:44.257653000 +0100 -@@ -75,13 +75,28 @@ ++++ b/drivers/spi/spi_bitbang.c 2011-01-18 20:53:42.079449999 +0100 +@@ -49,12 +49,14 @@ + + struct spi_bitbang_cs { + unsigned nsecs; /* (clock cycle time)/2 */ +- u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs, ++ u32 (*txrx_word)(struct spi_device *spi, ++ unsigned bit_delay, unsigned byte_delay, + u32 word, u8 bits); + unsigned (*txrx_bufs)(struct spi_device *, + u32 (*txrx_word)( + struct spi_device *spi, +- unsigned nsecs, ++ unsigned bit_delay, ++ unsigned byte_delay, + u32 word, u8 bits), + unsigned, struct spi_transfer *); + }; +@@ -62,26 +64,42 @@ + static unsigned bitbang_txrx_8( + struct spi_device *spi, + u32 (*txrx_word)(struct spi_device *spi, +- unsigned nsecs, ++ unsigned bit_delay, unsigned byte_delay, + u32 word, u8 bits), +- unsigned ns, ++ unsigned bit_delay, + struct spi_transfer *t + ) { + unsigned bits = spi->bits_per_word; + unsigned count = t->len; + const u8 *tx = t->tx_buf; + u8 *rx = t->rx_buf; ++ unsigned byte_delay = spi->delay_usecs; + while (likely(count > 0)) { u8 word = 0; - if (tx) + if (unlikely(tx)) word = *tx++; - word = txrx_word(spi, ns, word, bits); +- word = txrx_word(spi, ns, word, bits); - if (rx) ++ word = txrx_word(spi, bit_delay, byte_delay, word, bits); + if (likely(rx)) { + /* If we receive a 0x00, fetch one extra byte to sync + the state machine, then break out of the while loop. */ + if (unlikely(!word)) { -+ txrx_word(spi, ns, 0x00, bits); /* discard */ ++ txrx_word(spi, bit_delay, byte_delay, 0x00, bits); /* discard */ + break; + } + @@ -37,14 +178,38 @@ + + if (unlikely(tx)) { + /* Signal the end of tx by sending two 0x00's. */ -+ txrx_word(spi, ns, 0x00, bits); -+ txrx_word(spi, ns, 0x00, bits); ++ txrx_word(spi, bit_delay, byte_delay, 0x00, bits); ++ txrx_word(spi, bit_delay, byte_delay, 0x00, bits); + } + return t->len - count; } -@@ -346,12 +361,6 @@ +@@ -156,10 +174,10 @@ + bits_per_word = spi->bits_per_word; + if (bits_per_word <= 8) + cs->txrx_bufs = bitbang_txrx_8; +- else if (bits_per_word <= 16) ++/* else if (bits_per_word <= 16) + cs->txrx_bufs = bitbang_txrx_16; + else if (bits_per_word <= 32) +- cs->txrx_bufs = bitbang_txrx_32; ++ cs->txrx_bufs = bitbang_txrx_32; */ + else + return -EINVAL; + +@@ -167,8 +185,8 @@ + if (!hz) + hz = spi->max_speed_hz; + if (hz) { +- cs->nsecs = (1000000000/2) / hz; +- if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000)) ++ cs->nsecs = (1000000/2) / hz; ++ if (cs->nsecs > (MAX_UDELAY_MS * 1000)) + return -EINVAL; + } + +@@ -346,12 +364,6 @@ } if (status > 0) m->actual_length += status; @@ -57,3 +222,41 @@ status = 0; /* protocol tweaks before next transfer */ +--- a/drivers/spi/spi_gpio.c 2010-12-14 01:02:26.673204002 +0100 ++++ b/drivers/spi/spi_gpio.c 2011-01-18 13:29:17.915450000 +0100 +@@ -156,27 +156,27 @@ + */ + + static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, +- unsigned nsecs, u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, u32 word, u8 bits) + { +- return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); ++ return bitbang_txrx_be_cpha0(spi, bit_delay, byte_delay, 0, word, bits); + } + + static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, +- unsigned nsecs, u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, u32 word, u8 bits) + { +- return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); ++ return bitbang_txrx_be_cpha1(spi, bit_delay, byte_delay, 0, word, bits); + } + + static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, +- unsigned nsecs, u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, u32 word, u8 bits) + { +- return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); ++ return bitbang_txrx_be_cpha0(spi, bit_delay, byte_delay, 1, word, bits); + } + + static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, +- unsigned nsecs, u32 word, u8 bits) ++ unsigned bit_delay, unsigned byte_delay, u32 word, u8 bits) + { +- return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); ++ return bitbang_txrx_be_cpha1(spi, bit_delay, byte_delay, 1, word, bits); + } + + /*----------------------------------------------------------------------*/