[spidev + nixio + fluksod] allow the bitbanged spi max speed and inter-byte delay to be dynamically set from user space
This commit is contained in:
parent
d208545000
commit
0d3f076b5f
|
@ -37,10 +37,10 @@ local SPI_MAX_READ_BYTES = 256
|
|||
-- Attributes:
|
||||
-- { to = ctrl | delta | uart
|
||||
-- body = <string>
|
||||
-- parsed = { <command>, <arg1>, <arg2>, ... }
|
||||
-- parsed = { 'cmd' = <command>, 1 = <arg1>, 2 = <arg2>, ... }
|
||||
-- encoded = <string>
|
||||
-- received = { raw = <string>, l = <string>, crc = <string>, u = <string> }
|
||||
-- decoded = { l = ..., u = ... }
|
||||
-- decoded = { args = <string>, cmd = <string>, 1 = <arg1>, 2= <arg2>, ..., u = <string> }
|
||||
-- reply = <string>
|
||||
-- }
|
||||
--
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* nixio - Linux I/O library for lua
|
||||
*
|
||||
* Copyright (C) 2011 Bart Van Der Meerssche <bart.vandermeerssche@flukso.net>
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
/* 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");
|
||||
}
|
|
@ -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,
|
||||
+},
|
||||
+};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
|
Loading…
Reference in New Issue