Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
Linux
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
jan.koester
Linux
Commits
56afdb70
Commit
56afdb70
authored
9 years ago
by
Mark Brown
Browse files
Options
Downloads
Plain Diff
Merge remote-tracking branches 'spi/topic/spidev' and 'spi/topic/spidev-test' into spi-next
parents
165f2288
956b200a
30061915
Loading
Loading
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
Documentation/spi/spidev_test.c
+95
-20
95 additions, 20 deletions
Documentation/spi/spidev_test.c
drivers/spi/spidev.c
+43
-12
43 additions, 12 deletions
drivers/spi/spidev.c
with
138 additions
and
32 deletions
Documentation/spi/spidev_test.c
+
95
−
20
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
);
...
...
This diff is collapsed.
Click to expand it.
drivers/spi/spidev.c
+
43
−
12
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"
,
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment