Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
56afdb70
Commit
56afdb70
authored
Apr 11, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branches 'spi/topic/spidev' and 'spi/topic/spidev-test' into spi-next
parents
165f2288
956b200a
30061915
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
138 additions
and
32 deletions
+138
-32
Documentation/spi/spidev_test.c
Documentation/spi/spidev_test.c
+95
-20
drivers/spi/spidev.c
drivers/spi/spidev.c
+43
-12
No files found.
Documentation/spi/spidev_test.c
View file @
56afdb70
...
...
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
...
...
@@ -34,24 +35,79 @@ static uint32_t mode;
static
uint8_t
bits
=
8
;
static
uint32_t
speed
=
500000
;
static
uint16_t
delay
;
static
int
verbose
;
static
void
transfer
(
int
fd
)
uint8_t
default_tx
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0x40
,
0x00
,
0x00
,
0x00
,
0x00
,
0x95
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xF0
,
0x0D
,
};
uint8_t
default_rx
[
ARRAY_SIZE
(
default_tx
)]
=
{
0
,
};
char
*
input_tx
;
static
void
hex_dump
(
const
void
*
src
,
size_t
length
,
size_t
line_size
,
char
*
prefix
)
{
int
i
=
0
;
const
unsigned
char
*
address
=
src
;
const
unsigned
char
*
line
=
address
;
unsigned
char
c
;
printf
(
"%s | "
,
prefix
);
while
(
length
--
>
0
)
{
printf
(
"%02X "
,
*
address
++
);
if
(
!
(
++
i
%
line_size
)
||
(
length
==
0
&&
i
%
line_size
))
{
if
(
length
==
0
)
{
while
(
i
++
%
line_size
)
printf
(
"__ "
);
}
printf
(
" | "
);
/* right close */
while
(
line
<
address
)
{
c
=
*
line
++
;
printf
(
"%c"
,
(
c
<
33
||
c
==
255
)
?
0x2E
:
c
);
}
printf
(
"
\n
"
);
if
(
length
>
0
)
printf
(
"%s | "
,
prefix
);
}
}
}
/*
* Unescape - process hexadecimal escape character
* converts shell input "\x23" -> 0x23
*/
int
unespcape
(
char
*
_dst
,
char
*
_src
,
size_t
len
)
{
int
ret
=
0
;
char
*
src
=
_src
;
char
*
dst
=
_dst
;
unsigned
int
ch
;
while
(
*
src
)
{
if
(
*
src
==
'\\'
&&
*
(
src
+
1
)
==
'x'
)
{
sscanf
(
src
+
2
,
"%2x"
,
&
ch
);
src
+=
4
;
*
dst
++
=
(
unsigned
char
)
ch
;
}
else
{
*
dst
++
=
*
src
++
;
}
ret
++
;
}
return
ret
;
}
static
void
transfer
(
int
fd
,
uint8_t
const
*
tx
,
uint8_t
const
*
rx
,
size_t
len
)
{
int
ret
;
uint8_t
tx
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0x40
,
0x00
,
0x00
,
0x00
,
0x00
,
0x95
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xDE
,
0xAD
,
0xBE
,
0xEF
,
0xBA
,
0xAD
,
0xF0
,
0x0D
,
};
uint8_t
rx
[
ARRAY_SIZE
(
tx
)]
=
{
0
,
};
struct
spi_ioc_transfer
tr
=
{
.
tx_buf
=
(
unsigned
long
)
tx
,
.
rx_buf
=
(
unsigned
long
)
rx
,
.
len
=
ARRAY_SIZE
(
tx
)
,
.
len
=
len
,
.
delay_usecs
=
delay
,
.
speed_hz
=
speed
,
.
bits_per_word
=
bits
,
...
...
@@ -76,12 +132,9 @@ static void transfer(int fd)
if
(
ret
<
1
)
pabort
(
"can't send spi message"
);
for
(
ret
=
0
;
ret
<
ARRAY_SIZE
(
tx
);
ret
++
)
{
if
(
!
(
ret
%
6
))
puts
(
""
);
printf
(
"%.2X "
,
rx
[
ret
]);
}
puts
(
""
);
if
(
verbose
)
hex_dump
(
tx
,
len
,
32
,
"TX"
);
hex_dump
(
rx
,
len
,
32
,
"RX"
);
}
static
void
print_usage
(
const
char
*
prog
)
...
...
@@ -97,6 +150,8 @@ static void print_usage(const char *prog)
" -L --lsb least significant bit first
\n
"
" -C --cs-high chip select active high
\n
"
" -3 --3wire SI/SO signals shared
\n
"
" -v --verbose Verbose (show tx buffer)
\n
"
" -p Send data (e.g.
\"
1234
\\
xde
\\
xad
\"
)
\n
"
" -N --no-cs no chip select
\n
"
" -R --ready slave pulls low to pause
\n
"
" -2 --dual dual transfer
\n
"
...
...
@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[])
{
"no-cs"
,
0
,
0
,
'N'
},
{
"ready"
,
0
,
0
,
'R'
},
{
"dual"
,
0
,
0
,
'2'
},
{
"verbose"
,
0
,
0
,
'v'
},
{
"quad"
,
0
,
0
,
'4'
},
{
NULL
,
0
,
0
,
0
},
};
int
c
;
c
=
getopt_long
(
argc
,
argv
,
"D:s:d:b:lHOLC3NR24"
,
lopts
,
NULL
);
c
=
getopt_long
(
argc
,
argv
,
"D:s:d:b:lHOLC3NR24
p:v
"
,
lopts
,
NULL
);
if
(
c
==
-
1
)
break
;
...
...
@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[])
case
'N'
:
mode
|=
SPI_NO_CS
;
break
;
case
'v'
:
verbose
=
1
;
break
;
case
'R'
:
mode
|=
SPI_READY
;
break
;
case
'p'
:
input_tx
=
optarg
;
break
;
case
'2'
:
mode
|=
SPI_TX_DUAL
;
break
;
...
...
@@ -191,6 +253,9 @@ int main(int argc, char *argv[])
{
int
ret
=
0
;
int
fd
;
uint8_t
*
tx
;
uint8_t
*
rx
;
int
size
;
parse_opts
(
argc
,
argv
);
...
...
@@ -235,7 +300,17 @@ int main(int argc, char *argv[])
printf
(
"bits per word: %d
\n
"
,
bits
);
printf
(
"max speed: %d Hz (%d KHz)
\n
"
,
speed
,
speed
/
1000
);
transfer
(
fd
);
if
(
input_tx
)
{
size
=
strlen
(
input_tx
+
1
);
tx
=
malloc
(
size
);
rx
=
malloc
(
size
);
size
=
unespcape
((
char
*
)
tx
,
input_tx
,
size
);
transfer
(
fd
,
tx
,
rx
,
size
);
free
(
rx
);
free
(
tx
);
}
else
{
transfer
(
fd
,
default_tx
,
default_rx
,
sizeof
(
default_tx
));
}
close
(
fd
);
...
...
drivers/spi/spidev.c
View file @
56afdb70
...
...
@@ -223,7 +223,7 @@ static int spidev_message(struct spidev_data *spidev,
struct
spi_transfer
*
k_xfers
;
struct
spi_transfer
*
k_tmp
;
struct
spi_ioc_transfer
*
u_tmp
;
unsigned
n
,
total
;
unsigned
n
,
total
,
tx_total
,
rx_total
;
u8
*
tx_buf
,
*
rx_buf
;
int
status
=
-
EFAULT
;
...
...
@@ -239,33 +239,52 @@ static int spidev_message(struct spidev_data *spidev,
tx_buf
=
spidev
->
tx_buffer
;
rx_buf
=
spidev
->
rx_buffer
;
total
=
0
;
tx_total
=
0
;
rx_total
=
0
;
for
(
n
=
n_xfers
,
k_tmp
=
k_xfers
,
u_tmp
=
u_xfers
;
n
;
n
--
,
k_tmp
++
,
u_tmp
++
)
{
k_tmp
->
len
=
u_tmp
->
len
;
total
+=
k_tmp
->
len
;
if
(
total
>
bufsiz
)
{
/* Since the function returns the total length of transfers
* on success, restrict the total to positive int values to
* avoid the return value looking like an error. Also check
* each transfer length to avoid arithmetic overflow.
*/
if
(
total
>
INT_MAX
||
k_tmp
->
len
>
INT_MAX
)
{
status
=
-
EMSGSIZE
;
goto
done
;
}
if
(
u_tmp
->
rx_buf
)
{
/* this transfer needs space in RX bounce buffer */
rx_total
+=
k_tmp
->
len
;
if
(
rx_total
>
bufsiz
)
{
status
=
-
EMSGSIZE
;
goto
done
;
}
k_tmp
->
rx_buf
=
rx_buf
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
u8
__user
*
)
(
uintptr_t
)
u_tmp
->
rx_buf
,
u_tmp
->
len
))
goto
done
;
rx_buf
+=
k_tmp
->
len
;
}
if
(
u_tmp
->
tx_buf
)
{
/* this transfer needs space in TX bounce buffer */
tx_total
+=
k_tmp
->
len
;
if
(
tx_total
>
bufsiz
)
{
status
=
-
EMSGSIZE
;
goto
done
;
}
k_tmp
->
tx_buf
=
tx_buf
;
if
(
copy_from_user
(
tx_buf
,
(
const
u8
__user
*
)
(
uintptr_t
)
u_tmp
->
tx_buf
,
u_tmp
->
len
))
goto
done
;
tx_buf
+=
k_tmp
->
len
;
}
tx_buf
+=
k_tmp
->
len
;
rx_buf
+=
k_tmp
->
len
;
k_tmp
->
cs_change
=
!!
u_tmp
->
cs_change
;
k_tmp
->
tx_nbits
=
u_tmp
->
tx_nbits
;
...
...
@@ -303,8 +322,8 @@ static int spidev_message(struct spidev_data *spidev,
status
=
-
EFAULT
;
goto
done
;
}
rx_buf
+=
u_tmp
->
len
;
}
rx_buf
+=
u_tmp
->
len
;
}
status
=
total
;
...
...
@@ -684,6 +703,14 @@ static const struct file_operations spidev_fops = {
static
struct
class
*
spidev_class
;
#ifdef CONFIG_OF
static
const
struct
of_device_id
spidev_dt_ids
[]
=
{
{
.
compatible
=
"rohm,dh2228fv"
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
spidev_dt_ids
);
#endif
/*-------------------------------------------------------------------------*/
static
int
spidev_probe
(
struct
spi_device
*
spi
)
...
...
@@ -692,6 +719,17 @@ static int spidev_probe(struct spi_device *spi)
int
status
;
unsigned
long
minor
;
/*
* spidev should never be referenced in DT without a specific
* compatbile string, it is a Linux implementation thing
* rather than a description of the hardware.
*/
if
(
spi
->
dev
.
of_node
&&
!
of_match_device
(
spidev_dt_ids
,
&
spi
->
dev
))
{
dev_err
(
&
spi
->
dev
,
"buggy DT: spidev listed directly in DT
\n
"
);
WARN_ON
(
spi
->
dev
.
of_node
&&
!
of_match_device
(
spidev_dt_ids
,
&
spi
->
dev
));
}
/* Allocate driver data */
spidev
=
kzalloc
(
sizeof
(
*
spidev
),
GFP_KERNEL
);
if
(
!
spidev
)
...
...
@@ -758,13 +796,6 @@ static int spidev_remove(struct spi_device *spi)
return
0
;
}
static
const
struct
of_device_id
spidev_dt_ids
[]
=
{
{
.
compatible
=
"rohm,dh2228fv"
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
spidev_dt_ids
);
static
struct
spi_driver
spidev_spi_driver
=
{
.
driver
=
{
.
name
=
"spidev"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment