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
Kirill Smelkov
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
Show 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 @@
...
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <unistd.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <getopt.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
...
@@ -34,24 +35,79 @@ static uint32_t mode;
...
@@ -34,24 +35,79 @@ static uint32_t mode;
static
uint8_t
bits
=
8
;
static
uint8_t
bits
=
8
;
static
uint32_t
speed
=
500000
;
static
uint32_t
speed
=
500000
;
static
uint16_t
delay
;
static
uint16_t
delay
;
static
int
verbose
;
static
void
transfer
(
int
fd
)
uint8_t
default_tx
[]
=
{
{
int
ret
;
uint8_t
tx
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0x40
,
0x00
,
0x00
,
0x00
,
0x00
,
0x95
,
0x40
,
0x00
,
0x00
,
0x00
,
0x00
,
0x95
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
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
,
0xF0
,
0x0D
,
};
};
uint8_t
rx
[
ARRAY_SIZE
(
tx
)]
=
{
0
,
};
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
;
struct
spi_ioc_transfer
tr
=
{
struct
spi_ioc_transfer
tr
=
{
.
tx_buf
=
(
unsigned
long
)
tx
,
.
tx_buf
=
(
unsigned
long
)
tx
,
.
rx_buf
=
(
unsigned
long
)
rx
,
.
rx_buf
=
(
unsigned
long
)
rx
,
.
len
=
ARRAY_SIZE
(
tx
)
,
.
len
=
len
,
.
delay_usecs
=
delay
,
.
delay_usecs
=
delay
,
.
speed_hz
=
speed
,
.
speed_hz
=
speed
,
.
bits_per_word
=
bits
,
.
bits_per_word
=
bits
,
...
@@ -76,12 +132,9 @@ static void transfer(int fd)
...
@@ -76,12 +132,9 @@ static void transfer(int fd)
if
(
ret
<
1
)
if
(
ret
<
1
)
pabort
(
"can't send spi message"
);
pabort
(
"can't send spi message"
);
for
(
ret
=
0
;
ret
<
ARRAY_SIZE
(
tx
);
ret
++
)
{
if
(
verbose
)
if
(
!
(
ret
%
6
))
hex_dump
(
tx
,
len
,
32
,
"TX"
);
puts
(
""
);
hex_dump
(
rx
,
len
,
32
,
"RX"
);
printf
(
"%.2X "
,
rx
[
ret
]);
}
puts
(
""
);
}
}
static
void
print_usage
(
const
char
*
prog
)
static
void
print_usage
(
const
char
*
prog
)
...
@@ -97,6 +150,8 @@ 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
"
" -L --lsb least significant bit first
\n
"
" -C --cs-high chip select active high
\n
"
" -C --cs-high chip select active high
\n
"
" -3 --3wire SI/SO signals shared
\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
"
" -N --no-cs no chip select
\n
"
" -R --ready slave pulls low to pause
\n
"
" -R --ready slave pulls low to pause
\n
"
" -2 --dual dual transfer
\n
"
" -2 --dual dual transfer
\n
"
...
@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[])
...
@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[])
{
"no-cs"
,
0
,
0
,
'N'
},
{
"no-cs"
,
0
,
0
,
'N'
},
{
"ready"
,
0
,
0
,
'R'
},
{
"ready"
,
0
,
0
,
'R'
},
{
"dual"
,
0
,
0
,
'2'
},
{
"dual"
,
0
,
0
,
'2'
},
{
"verbose"
,
0
,
0
,
'v'
},
{
"quad"
,
0
,
0
,
'4'
},
{
"quad"
,
0
,
0
,
'4'
},
{
NULL
,
0
,
0
,
0
},
{
NULL
,
0
,
0
,
0
},
};
};
int
c
;
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
)
if
(
c
==
-
1
)
break
;
break
;
...
@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[])
...
@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[])
case
'N'
:
case
'N'
:
mode
|=
SPI_NO_CS
;
mode
|=
SPI_NO_CS
;
break
;
break
;
case
'v'
:
verbose
=
1
;
break
;
case
'R'
:
case
'R'
:
mode
|=
SPI_READY
;
mode
|=
SPI_READY
;
break
;
break
;
case
'p'
:
input_tx
=
optarg
;
break
;
case
'2'
:
case
'2'
:
mode
|=
SPI_TX_DUAL
;
mode
|=
SPI_TX_DUAL
;
break
;
break
;
...
@@ -191,6 +253,9 @@ int main(int argc, char *argv[])
...
@@ -191,6 +253,9 @@ int main(int argc, char *argv[])
{
{
int
ret
=
0
;
int
ret
=
0
;
int
fd
;
int
fd
;
uint8_t
*
tx
;
uint8_t
*
rx
;
int
size
;
parse_opts
(
argc
,
argv
);
parse_opts
(
argc
,
argv
);
...
@@ -235,7 +300,17 @@ int main(int argc, char *argv[])
...
@@ -235,7 +300,17 @@ int main(int argc, char *argv[])
printf
(
"bits per word: %d
\n
"
,
bits
);
printf
(
"bits per word: %d
\n
"
,
bits
);
printf
(
"max speed: %d Hz (%d KHz)
\n
"
,
speed
,
speed
/
1000
);
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
);
close
(
fd
);
...
...
drivers/spi/spidev.c
View file @
56afdb70
...
@@ -223,7 +223,7 @@ static int spidev_message(struct spidev_data *spidev,
...
@@ -223,7 +223,7 @@ static int spidev_message(struct spidev_data *spidev,
struct
spi_transfer
*
k_xfers
;
struct
spi_transfer
*
k_xfers
;
struct
spi_transfer
*
k_tmp
;
struct
spi_transfer
*
k_tmp
;
struct
spi_ioc_transfer
*
u_tmp
;
struct
spi_ioc_transfer
*
u_tmp
;
unsigned
n
,
total
;
unsigned
n
,
total
,
tx_total
,
rx_total
;
u8
*
tx_buf
,
*
rx_buf
;
u8
*
tx_buf
,
*
rx_buf
;
int
status
=
-
EFAULT
;
int
status
=
-
EFAULT
;
...
@@ -239,33 +239,52 @@ static int spidev_message(struct spidev_data *spidev,
...
@@ -239,33 +239,52 @@ static int spidev_message(struct spidev_data *spidev,
tx_buf
=
spidev
->
tx_buffer
;
tx_buf
=
spidev
->
tx_buffer
;
rx_buf
=
spidev
->
rx_buffer
;
rx_buf
=
spidev
->
rx_buffer
;
total
=
0
;
total
=
0
;
tx_total
=
0
;
rx_total
=
0
;
for
(
n
=
n_xfers
,
k_tmp
=
k_xfers
,
u_tmp
=
u_xfers
;
for
(
n
=
n_xfers
,
k_tmp
=
k_xfers
,
u_tmp
=
u_xfers
;
n
;
n
;
n
--
,
k_tmp
++
,
u_tmp
++
)
{
n
--
,
k_tmp
++
,
u_tmp
++
)
{
k_tmp
->
len
=
u_tmp
->
len
;
k_tmp
->
len
=
u_tmp
->
len
;
total
+=
k_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
;
status
=
-
EMSGSIZE
;
goto
done
;
goto
done
;
}
}
if
(
u_tmp
->
rx_buf
)
{
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
;
k_tmp
->
rx_buf
=
rx_buf
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
u8
__user
*
)
if
(
!
access_ok
(
VERIFY_WRITE
,
(
u8
__user
*
)
(
uintptr_t
)
u_tmp
->
rx_buf
,
(
uintptr_t
)
u_tmp
->
rx_buf
,
u_tmp
->
len
))
u_tmp
->
len
))
goto
done
;
goto
done
;
rx_buf
+=
k_tmp
->
len
;
}
}
if
(
u_tmp
->
tx_buf
)
{
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
;
k_tmp
->
tx_buf
=
tx_buf
;
if
(
copy_from_user
(
tx_buf
,
(
const
u8
__user
*
)
if
(
copy_from_user
(
tx_buf
,
(
const
u8
__user
*
)
(
uintptr_t
)
u_tmp
->
tx_buf
,
(
uintptr_t
)
u_tmp
->
tx_buf
,
u_tmp
->
len
))
u_tmp
->
len
))
goto
done
;
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
->
cs_change
=
!!
u_tmp
->
cs_change
;
k_tmp
->
tx_nbits
=
u_tmp
->
tx_nbits
;
k_tmp
->
tx_nbits
=
u_tmp
->
tx_nbits
;
...
@@ -303,9 +322,9 @@ static int spidev_message(struct spidev_data *spidev,
...
@@ -303,9 +322,9 @@ static int spidev_message(struct spidev_data *spidev,
status
=
-
EFAULT
;
status
=
-
EFAULT
;
goto
done
;
goto
done
;
}
}
}
rx_buf
+=
u_tmp
->
len
;
rx_buf
+=
u_tmp
->
len
;
}
}
}
status
=
total
;
status
=
total
;
done:
done:
...
@@ -684,6 +703,14 @@ static const struct file_operations spidev_fops = {
...
@@ -684,6 +703,14 @@ static const struct file_operations spidev_fops = {
static
struct
class
*
spidev_class
;
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
)
static
int
spidev_probe
(
struct
spi_device
*
spi
)
...
@@ -692,6 +719,17 @@ static int spidev_probe(struct spi_device *spi)
...
@@ -692,6 +719,17 @@ static int spidev_probe(struct spi_device *spi)
int
status
;
int
status
;
unsigned
long
minor
;
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 */
/* Allocate driver data */
spidev
=
kzalloc
(
sizeof
(
*
spidev
),
GFP_KERNEL
);
spidev
=
kzalloc
(
sizeof
(
*
spidev
),
GFP_KERNEL
);
if
(
!
spidev
)
if
(
!
spidev
)
...
@@ -758,13 +796,6 @@ static int spidev_remove(struct spi_device *spi)
...
@@ -758,13 +796,6 @@ static int spidev_remove(struct spi_device *spi)
return
0
;
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
=
{
static
struct
spi_driver
spidev_spi_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"spidev"
,
.
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