[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:
|
-- Attributes:
|
||||||
-- { to = ctrl | delta | uart
|
-- { to = ctrl | delta | uart
|
||||||
-- body = <string>
|
-- body = <string>
|
||||||
-- parsed = { <command>, <arg1>, <arg2>, ... }
|
-- parsed = { 'cmd' = <command>, 1 = <arg1>, 2 = <arg2>, ... }
|
||||||
-- encoded = <string>
|
-- encoded = <string>
|
||||||
-- received = { raw = <string>, l = <string>, crc = <string>, u = <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>
|
-- reply = <string>
|
||||||
-- }
|
-- }
|
||||||
--
|
--
|
||||||
|
@ -54,7 +54,7 @@ end
|
||||||
function parse(msg)
|
function parse(msg)
|
||||||
msg.parsed = {}
|
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
|
for arg in msg.body:gmatch('%d+') do
|
||||||
msg.parsed[#msg.parsed + 1] = arg
|
msg.parsed[#msg.parsed + 1] = arg
|
||||||
end
|
end
|
||||||
|
@ -68,33 +68,33 @@ function encode(msg)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if msg.parsed[1] == 'gd' then
|
if msg.parsed.cmd == 'gd' then
|
||||||
msg.encoded = msg.parsed[1]
|
msg.encoded = msg.parsed.cmd
|
||||||
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
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
@ -116,15 +116,20 @@ function rx(msg, cdev)
|
||||||
msg.received.raw = cdev:read(SPI_MAX_READ_BYTES)
|
msg.received.raw = cdev:read(SPI_MAX_READ_BYTES)
|
||||||
msg.received.l, msg.received.u = msg.received.raw:match('^l(%w*)%.?u(%w*)%.?$')
|
msg.received.l, msg.received.u = msg.received.raw:match('^l(%w*)%.?u(%w*)%.?$')
|
||||||
-- protect against nil values when match should fail
|
-- 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 ''
|
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.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
|
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 = ''
|
msg.received.l = ''
|
||||||
|
else
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -137,43 +142,46 @@ function decode(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
if msg.received.l ~= '' then
|
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
|
if msg.decoded.cmd == 'gd' then
|
||||||
for i = 1, msg.decoded.largs:len() / 18 do
|
for i = 1, msg.decoded.args:len() / 18 do
|
||||||
msg.decoded[(i-1)*3 + 1] =
|
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] =
|
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] =
|
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
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,7 +72,7 @@ while true do
|
||||||
msg:rx(spidev)
|
msg:rx(spidev)
|
||||||
msg:decode()
|
msg:decode()
|
||||||
--> dbg.vardump(msg)
|
--> 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
|
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 \
|
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/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,)
|
$(if $(NIXIO_TLS),src/tls-crypto.o src/tls-context.o src/tls-socket.o,)
|
||||||
|
|
||||||
ifeq ($(NIXIO_TLS),axtls)
|
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) {
|
static int nixio_file_seek(lua_State *L) {
|
||||||
int fd = nixio__checkfd(L, 1);
|
int fd = nixio__checkfd(L, 1);
|
||||||
|
@ -412,7 +350,6 @@ static int nixio_file__tostring(lua_State *L) {
|
||||||
static const luaL_reg M[] = {
|
static const luaL_reg M[] = {
|
||||||
{"write", nixio_file_write},
|
{"write", nixio_file_write},
|
||||||
{"read", nixio_file_read},
|
{"read", nixio_file_read},
|
||||||
{"spiread", nixio_file_spi_read},
|
|
||||||
{"tell", nixio_file_tell},
|
{"tell", nixio_file_tell},
|
||||||
{"seek", nixio_file_seek},
|
{"seek", nixio_file_seek},
|
||||||
{"stat", nixio_file_stat},
|
{"stat", nixio_file_stat},
|
||||||
|
@ -428,7 +365,7 @@ static const luaL_reg M[] = {
|
||||||
static const luaL_reg R[] = {
|
static const luaL_reg R[] = {
|
||||||
{"dup", nixio_dup},
|
{"dup", nixio_dup},
|
||||||
{"open", nixio_open},
|
{"open", nixio_open},
|
||||||
{"open_flags", nixio_open_flags},
|
{"open_flags", nixio_open_flags},
|
||||||
{"pipe", nixio_pipe},
|
{"pipe", nixio_pipe},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -142,6 +142,7 @@ NIXIO_API int luaopen_nixio(lua_State *L) {
|
||||||
nixio_open_bin(L);
|
nixio_open_bin(L);
|
||||||
nixio_open_fs(L);
|
nixio_open_fs(L);
|
||||||
nixio_open_user(L);
|
nixio_open_user(L);
|
||||||
|
nixio_open_spi(L);
|
||||||
|
|
||||||
#ifndef NO_TLS
|
#ifndef NO_TLS
|
||||||
nixio_open_tls_crypto(L);
|
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_bin(lua_State *L);
|
||||||
void nixio_open_fs(lua_State *L);
|
void nixio_open_fs(lua_State *L);
|
||||||
void nixio_open_user(lua_State *L);
|
void nixio_open_user(lua_State *L);
|
||||||
|
void nixio_open_spi(lua_State *L);
|
||||||
|
|
||||||
#ifndef NO_TLS
|
#ifndef NO_TLS
|
||||||
void nixio_open_tls_crypto(lua_State *L);
|
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",
|
+ .modalias = "spidev",
|
||||||
+ .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT,
|
+ .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT,
|
||||||
+ .mode = SPI_MODE_0,
|
+ .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,
|
+ .bus_num = 0,
|
||||||
+},
|
+},
|
||||||
+};
|
+};
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
- .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT,
|
- .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT,
|
||||||
+ .controller_data = (void *) SPI_GPIO_CS,
|
+ .controller_data = (void *) SPI_GPIO_CS,
|
||||||
.mode = SPI_MODE_0,
|
.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,
|
.bus_num = 0,
|
||||||
|
|
|
@ -1,32 +1,173 @@
|
||||||
--- a/drivers/spi/spi_gpio.c 2010-12-14 01:02:26.673204002 +0100
|
--- a/include/linux/spi/spi.h 2009-12-04 07:00:07.000000000 +0100
|
||||||
+++ b/drivers/spi/spi_gpio.c 2011-01-15 00:26:44.437652996 +0100
|
+++ b/include/linux/spi/spi.h 2011-01-18 14:30:48.919450001 +0100
|
||||||
@@ -158,7 +158,9 @@
|
@@ -68,6 +68,7 @@
|
||||||
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
|
struct device dev;
|
||||||
unsigned nsecs, u32 word, u8 bits)
|
struct spi_master *master;
|
||||||
{
|
u32 max_speed_hz;
|
||||||
- return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
|
+ u16 delay_usecs;
|
||||||
+ /* shift out a byte in 165us, then pause for 335us */
|
u8 chip_select;
|
||||||
+ ndelay(335);
|
u8 mode;
|
||||||
+ return bitbang_txrx_be_cpha0(spi, 5, 0, word, 8);
|
#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
|
--- 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
|
+++ b/drivers/spi/spi_bitbang.c 2011-01-18 20:53:42.079449999 +0100
|
||||||
@@ -75,13 +75,28 @@
|
@@ -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)) {
|
while (likely(count > 0)) {
|
||||||
u8 word = 0;
|
u8 word = 0;
|
||||||
|
|
||||||
- if (tx)
|
- if (tx)
|
||||||
+ if (unlikely(tx))
|
+ if (unlikely(tx))
|
||||||
word = *tx++;
|
word = *tx++;
|
||||||
word = txrx_word(spi, ns, word, bits);
|
- word = txrx_word(spi, ns, word, bits);
|
||||||
- if (rx)
|
- if (rx)
|
||||||
|
+ word = txrx_word(spi, bit_delay, byte_delay, word, bits);
|
||||||
+ if (likely(rx)) {
|
+ if (likely(rx)) {
|
||||||
+ /* If we receive a 0x00, fetch one extra byte to sync
|
+ /* If we receive a 0x00, fetch one extra byte to sync
|
||||||
+ the state machine, then break out of the while loop. */
|
+ the state machine, then break out of the while loop. */
|
||||||
+ if (unlikely(!word)) {
|
+ if (unlikely(!word)) {
|
||||||
+ txrx_word(spi, ns, 0x00, bits); /* discard */
|
+ txrx_word(spi, bit_delay, byte_delay, 0x00, bits); /* discard */
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
@ -37,14 +178,38 @@
|
||||||
+
|
+
|
||||||
+ if (unlikely(tx)) {
|
+ if (unlikely(tx)) {
|
||||||
+ /* Signal the end of tx by sending two 0x00's. */
|
+ /* Signal the end of tx by sending two 0x00's. */
|
||||||
+ txrx_word(spi, ns, 0x00, bits);
|
+ txrx_word(spi, bit_delay, byte_delay, 0x00, bits);
|
||||||
+ txrx_word(spi, ns, 0x00, bits);
|
+ txrx_word(spi, bit_delay, byte_delay, 0x00, bits);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
return t->len - count;
|
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)
|
if (status > 0)
|
||||||
m->actual_length += status;
|
m->actual_length += status;
|
||||||
|
@ -57,3 +222,41 @@
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
/* protocol tweaks before next transfer */
|
/* 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