Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
c974a9e5
Commit
c974a9e5
authored
Jan 21, 2008
by
Jesper Nilsson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CRIS v10: Add synchronous serial port driver for CRIS v10.
parent
4f073eff
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1473 additions
and
0 deletions
+1473
-0
arch/cris/Kconfig
arch/cris/Kconfig
+31
-0
arch/cris/arch-v10/drivers/Makefile
arch/cris/arch-v10/drivers/Makefile
+1
-0
arch/cris/arch-v10/drivers/sync_serial.c
arch/cris/arch-v10/drivers/sync_serial.c
+1441
-0
No files found.
arch/cris/Kconfig
View file @
c974a9e5
...
...
@@ -292,6 +292,37 @@ config ETRAX_PCF8563
endchoice
config ETRAX_SYNCHRONOUS_SERIAL
bool "Synchronous serial-port support"
help
Select this to enable the synchronous serial port driver.
config ETRAX_SYNCHRONOUS_SERIAL_PORT0
bool "Synchronous serial port 0 enabled"
depends on ETRAX_SYNCHRONOUS_SERIAL
help
Enabled synchronous serial port 0.
config ETRAX_SYNCHRONOUS_SERIAL0_DMA
bool "Enable DMA on synchronous serial port 0."
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0
help
A synchronous serial port can run in manual or DMA mode.
Selecting this option will make it run in DMA mode.
config ETRAX_SYNCHRONOUS_SERIAL_PORT1
bool "Synchronous serial port 1 enabled"
depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10)
help
Enabled synchronous serial port 1.
config ETRAX_SYNCHRONOUS_SERIAL1_DMA
bool "Enable DMA on synchronous serial port 1."
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1
help
A synchronous serial port can run in manual or DMA mode.
Selecting this option will make it run in DMA mode.
choice
prompt "Network LED behavior"
depends on ETRAX_ETHERNET
...
...
arch/cris/arch-v10/drivers/Makefile
View file @
c974a9e5
...
...
@@ -8,4 +8,5 @@ obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o
obj-$(CONFIG_ETRAX_GPIO)
+=
gpio.o
obj-$(CONFIG_ETRAX_DS1302)
+=
ds1302.o
obj-$(CONFIG_ETRAX_PCF8563)
+=
pcf8563.o
obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)
+=
sync_serial.o
arch/cris/arch-v10/drivers/sync_serial.c
0 → 100644
View file @
c974a9e5
/*
* Simple synchronous serial port driver for ETRAX 100LX.
*
* Synchronous serial ports are used for continuous streamed data like audio.
* The default setting for this driver is compatible with the STA 013 MP3
* decoder. The driver can easily be tuned to fit other audio encoder/decoders
* and SPI
*
* Copyright (c) 2001-2008 Axis Communications AB
*
* Author: Mikael Starvik, Johan Adolfsson
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/arch/svinto.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sync_serial.h>
#include <asm/arch/io_interface_mux.h>
/* The receiver is a bit tricky beacuse of the continuous stream of data.*/
/* */
/* Three DMA descriptors are linked together. Each DMA descriptor is */
/* responsible for port->bufchunk of a common buffer. */
/* */
/* +---------------------------------------------+ */
/* | +----------+ +----------+ +----------+ | */
/* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+ */
/* +----------+ +----------+ +----------+ */
/* | | | */
/* v v v */
/* +-------------------------------------+ */
/* | BUFFER | */
/* +-------------------------------------+ */
/* |<- data_avail ->| */
/* readp writep */
/* */
/* If the application keeps up the pace readp will be right after writep.*/
/* If the application can't keep the pace we have to throw away data. */
/* The idea is that readp should be ready with the data pointed out by */
/* Descr[i] when the DMA has filled in Descr[i+1]. */
/* Otherwise we will discard */
/* the rest of the data pointed out by Descr1 and set readp to the start */
/* of Descr2 */
#define SYNC_SERIAL_MAJOR 125
/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */
/* words can be handled */
#define IN_BUFFER_SIZE 12288
#define IN_DESCR_SIZE 256
#define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)
#define OUT_BUFFER_SIZE 4096
#define DEFAULT_FRAME_RATE 0
#define DEFAULT_WORD_RATE 7
/* NOTE: Enabling some debug will likely cause overrun or underrun,
* especially if manual mode is use.
*/
#define DEBUG(x)
#define DEBUGREAD(x)
#define DEBUGWRITE(x)
#define DEBUGPOLL(x)
#define DEBUGRXINT(x)
#define DEBUGTXINT(x)
/* Define some macros to access ETRAX 100 registers */
#define SETF(var, reg, field, val) \
do { \
var = (var & ~IO_MASK_(reg##_, field##_)) | \
IO_FIELD_(reg##_, field##_, val); \
} while (0)
#define SETS(var, reg, field, val) \
do { \
var = (var & ~IO_MASK_(reg##_, field##_)) | \
IO_STATE_(reg##_, field##_, _##val); \
} while (0)
struct
sync_port
{
/* Etrax registers and bits*/
const
volatile
unsigned
*
const
status
;
volatile
unsigned
*
const
ctrl_data
;
volatile
unsigned
*
const
output_dma_first
;
volatile
unsigned
char
*
const
output_dma_cmd
;
volatile
unsigned
char
*
const
output_dma_clr_irq
;
volatile
unsigned
*
const
input_dma_first
;
volatile
unsigned
char
*
const
input_dma_cmd
;
volatile
unsigned
*
const
input_dma_descr
;
/* 8*4 */
volatile
unsigned
char
*
const
input_dma_clr_irq
;
volatile
unsigned
*
const
data_out
;
const
volatile
unsigned
*
const
data_in
;
char
data_avail_bit
;
/* In R_IRQ_MASK1_RD/SET/CLR */
char
transmitter_ready_bit
;
/* In R_IRQ_MASK1_RD/SET/CLR */
char
input_dma_descr_bit
;
/* In R_IRQ_MASK2_RD */
char
output_dma_bit
;
/* In R_IRQ_MASK2_RD */
/* End of fields initialised in array */
char
started
;
/* 1 if port has been started */
char
port_nbr
;
/* Port 0 or 1 */
char
busy
;
/* 1 if port is busy */
char
enabled
;
/* 1 if port is enabled */
char
use_dma
;
/* 1 if port uses dma */
char
tr_running
;
char
init_irqs
;
/* Register shadow */
unsigned
int
ctrl_data_shadow
;
/* Remaining bytes for current transfer */
volatile
unsigned
int
out_count
;
/* Current position in out_buffer */
unsigned
char
*
outp
;
/* 16*4 */
/* Next byte to be read by application */
volatile
unsigned
char
*
volatile
readp
;
/* Next byte to be written by etrax */
volatile
unsigned
char
*
volatile
writep
;
unsigned
int
in_buffer_size
;
unsigned
int
inbufchunk
;
struct
etrax_dma_descr
out_descr
__attribute__
((
aligned
(
32
)));
struct
etrax_dma_descr
in_descr
[
NUM_IN_DESCR
]
__attribute__
((
aligned
(
32
)));
unsigned
char
out_buffer
[
OUT_BUFFER_SIZE
]
__attribute__
((
aligned
(
32
)));
unsigned
char
in_buffer
[
IN_BUFFER_SIZE
]
__attribute__
((
aligned
(
32
)));
unsigned
char
flip
[
IN_BUFFER_SIZE
]
__attribute__
((
aligned
(
32
)));
struct
etrax_dma_descr
*
next_rx_desc
;
struct
etrax_dma_descr
*
prev_rx_desc
;
int
full
;
wait_queue_head_t
out_wait_q
;
wait_queue_head_t
in_wait_q
;
};
static
int
etrax_sync_serial_init
(
void
);
static
void
initialize_port
(
int
portnbr
);
static
inline
int
sync_data_avail
(
struct
sync_port
*
port
);
static
int
sync_serial_open
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
sync_serial_release
(
struct
inode
*
inode
,
struct
file
*
file
);
static
unsigned
int
sync_serial_poll
(
struct
file
*
filp
,
poll_table
*
wait
);
static
int
sync_serial_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
static
ssize_t
sync_serial_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
);
static
ssize_t
sync_serial_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
);
#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)))
#define SYNC_SER_DMA
#endif
static
void
send_word
(
struct
sync_port
*
port
);
static
void
start_dma
(
struct
sync_port
*
port
,
const
char
*
data
,
int
count
);
static
void
start_dma_in
(
struct
sync_port
*
port
);
#ifdef SYNC_SER_DMA
static
irqreturn_t
tr_interrupt
(
int
irq
,
void
*
dev_id
);
static
irqreturn_t
rx_interrupt
(
int
irq
,
void
*
dev_id
);
#endif
#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)))
#define SYNC_SER_MANUAL
#endif
#ifdef SYNC_SER_MANUAL
static
irqreturn_t
manual_interrupt
(
int
irq
,
void
*
dev_id
);
#endif
/* The ports */
static
struct
sync_port
ports
[]
=
{
{
.
status
=
R_SYNC_SERIAL1_STATUS
,
.
ctrl_data
=
R_SYNC_SERIAL1_CTRL
,
.
output_dma_first
=
R_DMA_CH8_FIRST
,
.
output_dma_cmd
=
R_DMA_CH8_CMD
,
.
output_dma_clr_irq
=
R_DMA_CH8_CLR_INTR
,
.
input_dma_first
=
R_DMA_CH9_FIRST
,
.
input_dma_cmd
=
R_DMA_CH9_CMD
,
.
input_dma_descr
=
R_DMA_CH9_DESCR
,
.
input_dma_clr_irq
=
R_DMA_CH9_CLR_INTR
,
.
data_out
=
R_SYNC_SERIAL1_TR_DATA
,
.
data_in
=
R_SYNC_SERIAL1_REC_DATA
,
.
data_avail_bit
=
IO_BITNR
(
R_IRQ_MASK1_RD
,
ser1_data
),
.
transmitter_ready_bit
=
IO_BITNR
(
R_IRQ_MASK1_RD
,
ser1_ready
),
.
input_dma_descr_bit
=
IO_BITNR
(
R_IRQ_MASK2_RD
,
dma9_descr
),
.
output_dma_bit
=
IO_BITNR
(
R_IRQ_MASK2_RD
,
dma8_eop
),
.
init_irqs
=
1
,
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
.
use_dma
=
1
,
#else
.
use_dma
=
0
,
#endif
},
{
.
status
=
R_SYNC_SERIAL3_STATUS
,
.
ctrl_data
=
R_SYNC_SERIAL3_CTRL
,
.
output_dma_first
=
R_DMA_CH4_FIRST
,
.
output_dma_cmd
=
R_DMA_CH4_CMD
,
.
output_dma_clr_irq
=
R_DMA_CH4_CLR_INTR
,
.
input_dma_first
=
R_DMA_CH5_FIRST
,
.
input_dma_cmd
=
R_DMA_CH5_CMD
,
.
input_dma_descr
=
R_DMA_CH5_DESCR
,
.
input_dma_clr_irq
=
R_DMA_CH5_CLR_INTR
,
.
data_out
=
R_SYNC_SERIAL3_TR_DATA
,
.
data_in
=
R_SYNC_SERIAL3_REC_DATA
,
.
data_avail_bit
=
IO_BITNR
(
R_IRQ_MASK1_RD
,
ser3_data
),
.
transmitter_ready_bit
=
IO_BITNR
(
R_IRQ_MASK1_RD
,
ser3_ready
),
.
input_dma_descr_bit
=
IO_BITNR
(
R_IRQ_MASK2_RD
,
dma5_descr
),
.
output_dma_bit
=
IO_BITNR
(
R_IRQ_MASK2_RD
,
dma4_eop
),
.
init_irqs
=
1
,
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
.
use_dma
=
1
,
#else
.
use_dma
=
0
,
#endif
}
};
/* Register shadows */
static
unsigned
sync_serial_prescale_shadow
;
#define NUMBER_OF_PORTS 2
static
struct
file_operations
sync_serial_fops
=
{
.
owner
=
THIS_MODULE
,
.
write
=
sync_serial_write
,
.
read
=
sync_serial_read
,
.
poll
=
sync_serial_poll
,
.
ioctl
=
sync_serial_ioctl
,
.
open
=
sync_serial_open
,
.
release
=
sync_serial_release
};
static
int
__init
etrax_sync_serial_init
(
void
)
{
ports
[
0
].
enabled
=
0
;
ports
[
1
].
enabled
=
0
;
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
if
(
cris_request_io_interface
(
if_sync_serial_1
,
"sync_ser1"
))
{
printk
(
KERN_CRIT
"ETRAX100LX sync_serial: "
"Could not allocate IO group for port %d
\n
"
,
0
);
return
-
EBUSY
;
}
#endif
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
if
(
cris_request_io_interface
(
if_sync_serial_3
,
"sync_ser3"
))
{
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
cris_free_io_interface
(
if_sync_serial_1
);
#endif
printk
(
KERN_CRIT
"ETRAX100LX sync_serial: "
"Could not allocate IO group for port %d
\n
"
,
1
);
return
-
EBUSY
;
}
#endif
if
(
register_chrdev
(
SYNC_SERIAL_MAJOR
,
"sync serial"
,
&
sync_serial_fops
)
<
0
)
{
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
cris_free_io_interface
(
if_sync_serial_3
);
#endif
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
cris_free_io_interface
(
if_sync_serial_1
);
#endif
printk
(
"unable to get major for synchronous serial port
\n
"
);
return
-
EBUSY
;
}
/* Deselect synchronous serial ports while configuring. */
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode1
,
async
);
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode3
,
async
);
*
R_GEN_CONFIG_II
=
gen_config_ii_shadow
;
/* Initialize Ports */
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
ports
[
0
].
enabled
=
1
;
SETS
(
port_pb_i2c_shadow
,
R_PORT_PB_I2C
,
syncser1
,
ss1extra
);
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode1
,
sync
);
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
ports
[
0
].
use_dma
=
1
;
#else
ports
[
0
].
use_dma
=
0
;
#endif
initialize_port
(
0
);
#endif
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
ports
[
1
].
enabled
=
1
;
SETS
(
port_pb_i2c_shadow
,
R_PORT_PB_I2C
,
syncser3
,
ss3extra
);
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode3
,
sync
);
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
ports
[
1
].
use_dma
=
1
;
#else
ports
[
1
].
use_dma
=
0
;
#endif
initialize_port
(
1
);
#endif
*
R_PORT_PB_I2C
=
port_pb_i2c_shadow
;
/* Use PB4/PB7 */
/* Set up timing */
*
R_SYNC_SERIAL_PRESCALE
=
sync_serial_prescale_shadow
=
(
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u1
,
codec
)
|
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
word_stb_sel_u1
,
external
)
|
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u3
,
codec
)
|
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
word_stb_sel_u3
,
external
)
|
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
prescaler
,
div4
)
|
IO_FIELD
(
R_SYNC_SERIAL_PRESCALE
,
frame_rate
,
DEFAULT_FRAME_RATE
)
|
IO_FIELD
(
R_SYNC_SERIAL_PRESCALE
,
word_rate
,
DEFAULT_WORD_RATE
)
|
IO_STATE
(
R_SYNC_SERIAL_PRESCALE
,
warp_mode
,
normal
));
/* Select synchronous ports */
*
R_GEN_CONFIG_II
=
gen_config_ii_shadow
;
printk
(
KERN_INFO
"ETRAX 100LX synchronous serial port driver
\n
"
);
return
0
;
}
static
void
__init
initialize_port
(
int
portnbr
)
{
struct
sync_port
*
port
=
&
ports
[
portnbr
];
DEBUG
(
printk
(
KERN_DEBUG
"Init sync serial port %d
\n
"
,
portnbr
));
port
->
started
=
0
;
port
->
port_nbr
=
portnbr
;
port
->
busy
=
0
;
port
->
tr_running
=
0
;
port
->
out_count
=
0
;
port
->
outp
=
port
->
out_buffer
;
port
->
readp
=
port
->
flip
;
port
->
writep
=
port
->
flip
;
port
->
in_buffer_size
=
IN_BUFFER_SIZE
;
port
->
inbufchunk
=
IN_DESCR_SIZE
;
port
->
next_rx_desc
=
&
port
->
in_descr
[
0
];
port
->
prev_rx_desc
=
&
port
->
in_descr
[
NUM_IN_DESCR
-
1
];
port
->
prev_rx_desc
->
ctrl
=
d_eol
;
init_waitqueue_head
(
&
port
->
out_wait_q
);
init_waitqueue_head
(
&
port
->
in_wait_q
);
port
->
ctrl_data_shadow
=
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
tr_baud
,
c115k2Hz
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
mode
,
master_output
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
error
,
ignore
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
rec_enable
,
disable
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
f_synctype
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
f_syncsize
,
word
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
f_sync
,
on
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
clk_mode
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
clk_halt
,
stopped
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
bitorder
,
msb
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
tr_enable
,
disable
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size8bit
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
buf_empty
,
lmt_8
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
buf_full
,
lmt_8
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
flow_ctrl
,
enabled
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
clk_polarity
,
neg
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
frame_polarity
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
status_polarity
,
inverted
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
clk_driver
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
frame_driver
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
status_driver
,
normal
)
|
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
def_out0
,
high
);
if
(
port
->
use_dma
)
port
->
ctrl_data_shadow
|=
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
dma_enable
,
on
);
else
port
->
ctrl_data_shadow
|=
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
dma_enable
,
off
);
*
port
->
ctrl_data
=
port
->
ctrl_data_shadow
;
}
static
inline
int
sync_data_avail
(
struct
sync_port
*
port
)
{
int
avail
;
unsigned
char
*
start
;
unsigned
char
*
end
;
start
=
(
unsigned
char
*
)
port
->
readp
;
/* cast away volatile */
end
=
(
unsigned
char
*
)
port
->
writep
;
/* cast away volatile */
/* 0123456789 0123456789
* ----- - -----
* ^rp ^wp ^wp ^rp
*/
if
(
end
>=
start
)
avail
=
end
-
start
;
else
avail
=
port
->
in_buffer_size
-
(
start
-
end
);
return
avail
;
}
static
inline
int
sync_data_avail_to_end
(
struct
sync_port
*
port
)
{
int
avail
;
unsigned
char
*
start
;
unsigned
char
*
end
;
start
=
(
unsigned
char
*
)
port
->
readp
;
/* cast away volatile */
end
=
(
unsigned
char
*
)
port
->
writep
;
/* cast away volatile */
/* 0123456789 0123456789
* ----- -----
* ^rp ^wp ^wp ^rp
*/
if
(
end
>=
start
)
avail
=
end
-
start
;
else
avail
=
port
->
flip
+
port
->
in_buffer_size
-
start
;
return
avail
;
}
static
int
sync_serial_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
dev
=
MINOR
(
inode
->
i_rdev
);
struct
sync_port
*
port
;
int
mode
;
DEBUG
(
printk
(
KERN_DEBUG
"Open sync serial port %d
\n
"
,
dev
));
if
(
dev
<
0
||
dev
>=
NUMBER_OF_PORTS
||
!
ports
[
dev
].
enabled
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Invalid minor %d
\n
"
,
dev
));
return
-
ENODEV
;
}
port
=
&
ports
[
dev
];
/* Allow open this device twice (assuming one reader and one writer) */
if
(
port
->
busy
==
2
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Device is busy..
\n
"
));
return
-
EBUSY
;
}
if
(
port
->
init_irqs
)
{
if
(
port
->
use_dma
)
{
if
(
port
==
&
ports
[
0
])
{
#ifdef SYNC_SER_DMA
if
(
request_irq
(
24
,
tr_interrupt
,
0
,
"synchronous serial 1 dma tr"
,
&
ports
[
0
]))
{
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 1 IRQ"
);
return
-
EBUSY
;
}
else
if
(
request_irq
(
25
,
rx_interrupt
,
0
,
"synchronous serial 1 dma rx"
,
&
ports
[
0
]))
{
free_irq
(
24
,
&
port
[
0
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 1 IRQ"
);
return
-
EBUSY
;
}
else
if
(
cris_request_dma
(
8
,
"synchronous serial 1 dma tr"
,
DMA_VERBOSE_ON_ERROR
,
dma_ser1
))
{
free_irq
(
24
,
&
port
[
0
]);
free_irq
(
25
,
&
port
[
0
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 1 "
"TX DMA channel"
);
return
-
EBUSY
;
}
else
if
(
cris_request_dma
(
9
,
"synchronous serial 1 dma rec"
,
DMA_VERBOSE_ON_ERROR
,
dma_ser1
))
{
cris_free_dma
(
8
,
NULL
);
free_irq
(
24
,
&
port
[
0
]);
free_irq
(
25
,
&
port
[
0
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 1 "
"RX DMA channel"
);
return
-
EBUSY
;
}
#endif
RESET_DMA
(
8
);
WAIT_DMA
(
8
);
RESET_DMA
(
9
);
WAIT_DMA
(
9
);
*
R_DMA_CH8_CLR_INTR
=
IO_STATE
(
R_DMA_CH8_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH8_CLR_INTR
,
clr_descr
,
do
);
*
R_DMA_CH9_CLR_INTR
=
IO_STATE
(
R_DMA_CH9_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH9_CLR_INTR
,
clr_descr
,
do
);
*
R_IRQ_MASK2_SET
=
IO_STATE
(
R_IRQ_MASK2_SET
,
dma8_eop
,
set
)
|
IO_STATE
(
R_IRQ_MASK2_SET
,
dma9_descr
,
set
);
}
else
if
(
port
==
&
ports
[
1
])
{
#ifdef SYNC_SER_DMA
if
(
request_irq
(
20
,
tr_interrupt
,
0
,
"synchronous serial 3 dma tr"
,
&
ports
[
1
]))
{
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 3 IRQ"
);
return
-
EBUSY
;
}
else
if
(
request_irq
(
21
,
rx_interrupt
,
0
,
"synchronous serial 3 dma rx"
,
&
ports
[
1
]))
{
free_irq
(
20
,
&
ports
[
1
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 3 IRQ"
);
return
-
EBUSY
;
}
else
if
(
cris_request_dma
(
4
,
"synchronous serial 3 dma tr"
,
DMA_VERBOSE_ON_ERROR
,
dma_ser3
))
{
free_irq
(
21
,
&
ports
[
1
]);
free_irq
(
20
,
&
ports
[
1
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 3 "
"TX DMA channel"
);
return
-
EBUSY
;
}
else
if
(
cris_request_dma
(
5
,
"synchronous serial 3 dma rec"
,
DMA_VERBOSE_ON_ERROR
,
dma_ser3
))
{
cris_free_dma
(
4
,
NULL
);
free_irq
(
21
,
&
ports
[
1
]);
free_irq
(
20
,
&
ports
[
1
]);
printk
(
KERN_CRIT
"Can't alloc "
"sync serial port 3 "
"RX DMA channel"
);
return
-
EBUSY
;
}
#endif
RESET_DMA
(
4
);
WAIT_DMA
(
4
);
RESET_DMA
(
5
);
WAIT_DMA
(
5
);
*
R_DMA_CH4_CLR_INTR
=
IO_STATE
(
R_DMA_CH4_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH4_CLR_INTR
,
clr_descr
,
do
);
*
R_DMA_CH5_CLR_INTR
=
IO_STATE
(
R_DMA_CH5_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH5_CLR_INTR
,
clr_descr
,
do
);
*
R_IRQ_MASK2_SET
=
IO_STATE
(
R_IRQ_MASK2_SET
,
dma4_eop
,
set
)
|
IO_STATE
(
R_IRQ_MASK2_SET
,
dma5_descr
,
set
);
}
start_dma_in
(
port
);
port
->
init_irqs
=
0
;
}
else
{
/* !port->use_dma */
#ifdef SYNC_SER_MANUAL
if
(
port
==
&
ports
[
0
])
{
if
(
request_irq
(
8
,
manual_interrupt
,
IRQF_SHARED
|
IRQF_DISABLED
,
"synchronous serial manual irq"
,
&
ports
[
0
]))
{
printk
(
KERN_CRIT
"Can't alloc "
"sync serial manual irq"
);
return
-
EBUSY
;
}
}
else
if
(
port
==
&
ports
[
1
])
{
if
(
request_irq
(
8
,
manual_interrupt
,
IRQF_SHARED
|
IRQF_DISABLED
,
"synchronous serial manual irq"
,
&
ports
[
1
]))
{
printk
(
KERN_CRIT
"Can't alloc "
"sync serial manual irq"
);
return
-
EBUSY
;
}
}
port
->
init_irqs
=
0
;
#else
panic
(
"sync_serial: Manual mode not supported.
\n
"
);
#endif
/* SYNC_SER_MANUAL */
}
}
/* port->init_irqs */
port
->
busy
++
;
/* Start port if we use it as input */
mode
=
IO_EXTRACT
(
R_SYNC_SERIAL1_CTRL
,
mode
,
port
->
ctrl_data_shadow
);
if
(
mode
==
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
mode
,
master_input
)
||
mode
==
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
mode
,
slave_input
)
||
mode
==
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
mode
,
master_bidir
)
||
mode
==
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
mode
,
slave_bidir
))
{
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_halt
,
running
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
tr_enable
,
enable
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
rec_enable
,
enable
);
port
->
started
=
1
;
*
port
->
ctrl_data
=
port
->
ctrl_data_shadow
;
if
(
!
port
->
use_dma
)
*
R_IRQ_MASK1_SET
=
1
<<
port
->
data_avail_bit
;
DEBUG
(
printk
(
KERN_DEBUG
"sser%d rec started
\n
"
,
dev
));
}
return
0
;
}
static
int
sync_serial_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
dev
=
MINOR
(
inode
->
i_rdev
);
struct
sync_port
*
port
;
if
(
dev
<
0
||
dev
>=
NUMBER_OF_PORTS
||
!
ports
[
dev
].
enabled
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Invalid minor %d
\n
"
,
dev
));
return
-
ENODEV
;
}
port
=
&
ports
[
dev
];
if
(
port
->
busy
)
port
->
busy
--
;
if
(
!
port
->
busy
)
*
R_IRQ_MASK1_CLR
=
((
1
<<
port
->
data_avail_bit
)
|
(
1
<<
port
->
transmitter_ready_bit
));
return
0
;
}
static
unsigned
int
sync_serial_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
int
dev
=
MINOR
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
unsigned
int
mask
=
0
;
struct
sync_port
*
port
;
DEBUGPOLL
(
static
unsigned
int
prev_mask
=
0
);
port
=
&
ports
[
dev
];
poll_wait
(
file
,
&
port
->
out_wait_q
,
wait
);
poll_wait
(
file
,
&
port
->
in_wait_q
,
wait
);
/* Some room to write */
if
(
port
->
out_count
<
OUT_BUFFER_SIZE
)
mask
|=
POLLOUT
|
POLLWRNORM
;
/* At least an inbufchunk of data */
if
(
sync_data_avail
(
port
)
>=
port
->
inbufchunk
)
mask
|=
POLLIN
|
POLLRDNORM
;
DEBUGPOLL
(
if
(
mask
!=
prev_mask
)
printk
(
KERN_DEBUG
"sync_serial_poll: mask 0x%08X %s %s
\n
"
,
mask
,
mask
&
POLLOUT
?
"POLLOUT"
:
""
,
mask
&
POLLIN
?
"POLLIN"
:
""
);
prev_mask
=
mask
;
);
return
mask
;
}
static
int
sync_serial_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
return_val
=
0
;
unsigned
long
flags
;
int
dev
=
MINOR
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
struct
sync_port
*
port
;
if
(
dev
<
0
||
dev
>=
NUMBER_OF_PORTS
||
!
ports
[
dev
].
enabled
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Invalid minor %d
\n
"
,
dev
));
return
-
1
;
}
port
=
&
ports
[
dev
];
local_irq_save
(
flags
);
/* Disable port while changing config */
if
(
dev
)
{
if
(
port
->
use_dma
)
{
RESET_DMA
(
4
);
WAIT_DMA
(
4
);
port
->
tr_running
=
0
;
port
->
out_count
=
0
;
port
->
outp
=
port
->
out_buffer
;
*
R_DMA_CH4_CLR_INTR
=
IO_STATE
(
R_DMA_CH4_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH4_CLR_INTR
,
clr_descr
,
do
);
}
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode3
,
async
);
}
else
{
if
(
port
->
use_dma
)
{
RESET_DMA
(
8
);
WAIT_DMA
(
8
);
port
->
tr_running
=
0
;
port
->
out_count
=
0
;
port
->
outp
=
port
->
out_buffer
;
*
R_DMA_CH8_CLR_INTR
=
IO_STATE
(
R_DMA_CH8_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH8_CLR_INTR
,
clr_descr
,
do
);
}
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode1
,
async
);
}
*
R_GEN_CONFIG_II
=
gen_config_ii_shadow
;
local_irq_restore
(
flags
);
switch
(
cmd
)
{
case
SSP_SPEED
:
if
(
GET_SPEED
(
arg
)
==
CODEC
)
{
if
(
dev
)
SETS
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u3
,
codec
);
else
SETS
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u1
,
codec
);
SETF
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
prescaler
,
GET_FREQ
(
arg
));
SETF
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
frame_rate
,
GET_FRAME_RATE
(
arg
));
SETF
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
word_rate
,
GET_WORD_RATE
(
arg
));
}
else
{
SETF
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
tr_baud
,
GET_SPEED
(
arg
));
if
(
dev
)
SETS
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u3
,
baudrate
);
else
SETS
(
sync_serial_prescale_shadow
,
R_SYNC_SERIAL_PRESCALE
,
clk_sel_u1
,
baudrate
);
}
break
;
case
SSP_MODE
:
if
(
arg
>
5
)
return
-
EINVAL
;
if
(
arg
==
MASTER_OUTPUT
||
arg
==
SLAVE_OUTPUT
)
*
R_IRQ_MASK1_CLR
=
1
<<
port
->
data_avail_bit
;
else
if
(
!
port
->
use_dma
)
*
R_IRQ_MASK1_SET
=
1
<<
port
->
data_avail_bit
;
SETF
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
mode
,
arg
);
break
;
case
SSP_FRAME_SYNC
:
if
(
arg
&
NORMAL_SYNC
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_synctype
,
normal
);
else
if
(
arg
&
EARLY_SYNC
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_synctype
,
early
);
if
(
arg
&
BIT_SYNC
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_syncsize
,
bit
);
else
if
(
arg
&
WORD_SYNC
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_syncsize
,
word
);
else
if
(
arg
&
EXTENDED_SYNC
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_syncsize
,
extended
);
if
(
arg
&
SYNC_ON
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_sync
,
on
);
else
if
(
arg
&
SYNC_OFF
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_sync
,
off
);
if
(
arg
&
WORD_SIZE_8
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size8bit
);
else
if
(
arg
&
WORD_SIZE_12
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size12bit
);
else
if
(
arg
&
WORD_SIZE_16
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size16bit
);
else
if
(
arg
&
WORD_SIZE_24
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size24bit
);
else
if
(
arg
&
WORD_SIZE_32
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size32bit
);
if
(
arg
&
BIT_ORDER_MSB
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
bitorder
,
msb
);
else
if
(
arg
&
BIT_ORDER_LSB
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
bitorder
,
lsb
);
if
(
arg
&
FLOW_CONTROL_ENABLE
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
flow_ctrl
,
enabled
);
else
if
(
arg
&
FLOW_CONTROL_DISABLE
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
flow_ctrl
,
disabled
);
if
(
arg
&
CLOCK_NOT_GATED
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_mode
,
normal
);
else
if
(
arg
&
CLOCK_GATED
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_mode
,
gated
);
break
;
case
SSP_IPOLARITY
:
/* NOTE!! negedge is considered NORMAL */
if
(
arg
&
CLOCK_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_polarity
,
neg
);
else
if
(
arg
&
CLOCK_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_polarity
,
pos
);
if
(
arg
&
FRAME_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_polarity
,
normal
);
else
if
(
arg
&
FRAME_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_polarity
,
inverted
);
if
(
arg
&
STATUS_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
status_polarity
,
normal
);
else
if
(
arg
&
STATUS_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
status_polarity
,
inverted
);
break
;
case
SSP_OPOLARITY
:
if
(
arg
&
CLOCK_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_driver
,
normal
);
else
if
(
arg
&
CLOCK_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_driver
,
inverted
);
if
(
arg
&
FRAME_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_driver
,
normal
);
else
if
(
arg
&
FRAME_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_driver
,
inverted
);
if
(
arg
&
STATUS_NORMAL
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
status_driver
,
normal
);
else
if
(
arg
&
STATUS_INVERT
)
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
status_driver
,
inverted
);
break
;
case
SSP_SPI
:
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
flow_ctrl
,
disabled
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
bitorder
,
msb
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size8bit
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_sync
,
on
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_syncsize
,
word
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
f_synctype
,
normal
);
if
(
arg
&
SPI_SLAVE
)
{
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_polarity
,
inverted
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_polarity
,
neg
);
SETF
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
mode
,
SLAVE_INPUT
);
}
else
{
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
frame_driver
,
inverted
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_driver
,
inverted
);
SETF
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
mode
,
MASTER_OUTPUT
);
}
break
;
case
SSP_INBUFCHUNK
:
#if 0
if (arg > port->in_buffer_size/NUM_IN_DESCR)
return -EINVAL;
port->inbufchunk = arg;
/* Make sure in_buffer_size is a multiple of inbufchunk */
port->in_buffer_size =
(port->in_buffer_size/port->inbufchunk) *
port->inbufchunk;
DEBUG(printk(KERN_DEBUG "inbufchunk %i in_buffer_size: %i\n",
port->inbufchunk, port->in_buffer_size));
if (port->use_dma) {
if (port->port_nbr == 0) {
RESET_DMA(9);
WAIT_DMA(9);
} else {
RESET_DMA(5);
WAIT_DMA(5);
}
start_dma_in(port);
}
#endif
break
;
default:
return_val
=
-
1
;
}
/* Make sure we write the config without interruption */
local_irq_save
(
flags
);
/* Set config and enable port */
*
port
->
ctrl_data
=
port
->
ctrl_data_shadow
;
nop
();
nop
();
nop
();
nop
();
*
R_SYNC_SERIAL_PRESCALE
=
sync_serial_prescale_shadow
;
nop
();
nop
();
nop
();
nop
();
if
(
dev
)
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode3
,
sync
);
else
SETS
(
gen_config_ii_shadow
,
R_GEN_CONFIG_II
,
sermode1
,
sync
);
*
R_GEN_CONFIG_II
=
gen_config_ii_shadow
;
/* Reset DMA. At readout from serial port the data could be shifted
* one byte if not resetting DMA.
*/
if
(
port
->
use_dma
)
{
if
(
port
->
port_nbr
==
0
)
{
RESET_DMA
(
9
);
WAIT_DMA
(
9
);
}
else
{
RESET_DMA
(
5
);
WAIT_DMA
(
5
);
}
start_dma_in
(
port
);
}
local_irq_restore
(
flags
);
return
return_val
;
}
static
ssize_t
sync_serial_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
dev
=
MINOR
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
DECLARE_WAITQUEUE
(
wait
,
current
);
struct
sync_port
*
port
;
unsigned
long
flags
;
unsigned
long
c
,
c1
;
unsigned
long
free_outp
;
unsigned
long
outp
;
unsigned
long
out_buffer
;
if
(
dev
<
0
||
dev
>=
NUMBER_OF_PORTS
||
!
ports
[
dev
].
enabled
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Invalid minor %d
\n
"
,
dev
));
return
-
ENODEV
;
}
port
=
&
ports
[
dev
];
DEBUGWRITE
(
printk
(
KERN_DEBUG
"W d%d c %lu (%d/%d)
\n
"
,
port
->
port_nbr
,
count
,
port
->
out_count
,
OUT_BUFFER_SIZE
));
/* Space to end of buffer */
/*
* out_buffer <c1>012345<- c ->OUT_BUFFER_SIZE
* outp^ +out_count
* ^free_outp
* out_buffer 45<- c ->0123OUT_BUFFER_SIZE
* +out_count outp^
* free_outp
*
*/
/* Read variables that may be updated by interrupts */
local_irq_save
(
flags
);
if
(
count
>
OUT_BUFFER_SIZE
-
port
->
out_count
)
count
=
OUT_BUFFER_SIZE
-
port
->
out_count
;
outp
=
(
unsigned
long
)
port
->
outp
;
free_outp
=
outp
+
port
->
out_count
;
local_irq_restore
(
flags
);
out_buffer
=
(
unsigned
long
)
port
->
out_buffer
;
/* Find out where and how much to write */
if
(
free_outp
>=
out_buffer
+
OUT_BUFFER_SIZE
)
free_outp
-=
OUT_BUFFER_SIZE
;
if
(
free_outp
>=
outp
)
c
=
out_buffer
+
OUT_BUFFER_SIZE
-
free_outp
;
else
c
=
outp
-
free_outp
;
if
(
c
>
count
)
c
=
count
;
DEBUGWRITE
(
printk
(
KERN_DEBUG
"w op %08lX fop %08lX c %lu
\n
"
,
outp
,
free_outp
,
c
));
if
(
copy_from_user
((
void
*
)
free_outp
,
buf
,
c
))
return
-
EFAULT
;
if
(
c
!=
count
)
{
buf
+=
c
;
c1
=
count
-
c
;
DEBUGWRITE
(
printk
(
KERN_DEBUG
"w2 fi %lu c %lu c1 %lu
\n
"
,
free_outp
-
out_buffer
,
c
,
c1
));
if
(
copy_from_user
((
void
*
)
out_buffer
,
buf
,
c1
))
return
-
EFAULT
;
}
local_irq_save
(
flags
);
port
->
out_count
+=
count
;
local_irq_restore
(
flags
);
/* Make sure transmitter/receiver is running */
if
(
!
port
->
started
)
{
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_halt
,
running
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
tr_enable
,
enable
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
rec_enable
,
enable
);
port
->
started
=
1
;
}
*
port
->
ctrl_data
=
port
->
ctrl_data_shadow
;
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
local_irq_save
(
flags
);
if
(
!
port
->
tr_running
)
{
if
(
!
port
->
use_dma
)
{
/* Start sender by writing data */
send_word
(
port
);
/* and enable transmitter ready IRQ */
*
R_IRQ_MASK1_SET
=
1
<<
port
->
transmitter_ready_bit
;
}
else
start_dma
(
port
,
(
unsigned
char
*
volatile
)
port
->
outp
,
c
);
}
local_irq_restore
(
flags
);
DEBUGWRITE
(
printk
(
KERN_DEBUG
"w d%d c %lu NB
\n
"
,
port
->
port_nbr
,
count
));
return
count
;
}
/* Sleep until all sent */
add_wait_queue
(
&
port
->
out_wait_q
,
&
wait
);
set_current_state
(
TASK_INTERRUPTIBLE
);
local_irq_save
(
flags
);
if
(
!
port
->
tr_running
)
{
if
(
!
port
->
use_dma
)
{
/* Start sender by writing data */
send_word
(
port
);
/* and enable transmitter ready IRQ */
*
R_IRQ_MASK1_SET
=
1
<<
port
->
transmitter_ready_bit
;
}
else
start_dma
(
port
,
port
->
outp
,
c
);
}
local_irq_restore
(
flags
);
schedule
();
set_current_state
(
TASK_RUNNING
);
remove_wait_queue
(
&
port
->
out_wait_q
,
&
wait
);
if
(
signal_pending
(
current
))
return
-
EINTR
;
DEBUGWRITE
(
printk
(
KERN_DEBUG
"w d%d c %lu
\n
"
,
port
->
port_nbr
,
count
));
return
count
;
}
static
ssize_t
sync_serial_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
dev
=
MINOR
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
int
avail
;
struct
sync_port
*
port
;
unsigned
char
*
start
;
unsigned
char
*
end
;
unsigned
long
flags
;
if
(
dev
<
0
||
dev
>=
NUMBER_OF_PORTS
||
!
ports
[
dev
].
enabled
)
{
DEBUG
(
printk
(
KERN_DEBUG
"Invalid minor %d
\n
"
,
dev
));
return
-
ENODEV
;
}
port
=
&
ports
[
dev
];
DEBUGREAD
(
printk
(
KERN_DEBUG
"R%d c %d ri %lu wi %lu /%lu
\n
"
,
dev
,
count
,
port
->
readp
-
port
->
flip
,
port
->
writep
-
port
->
flip
,
port
->
in_buffer_size
));
if
(
!
port
->
started
)
{
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
clk_halt
,
running
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
tr_enable
,
enable
);
SETS
(
port
->
ctrl_data_shadow
,
R_SYNC_SERIAL1_CTRL
,
rec_enable
,
enable
);
port
->
started
=
1
;
}
*
port
->
ctrl_data
=
port
->
ctrl_data_shadow
;
/* Calculate number of available bytes */
/* Save pointers to avoid that they are modified by interrupt */
local_irq_save
(
flags
);
start
=
(
unsigned
char
*
)
port
->
readp
;
/* cast away volatile */
end
=
(
unsigned
char
*
)
port
->
writep
;
/* cast away volatile */
local_irq_restore
(
flags
);
while
(
start
==
end
&&
!
port
->
full
)
{
/* No data */
if
(
file
->
f_flags
&
O_NONBLOCK
)
return
-
EAGAIN
;
interruptible_sleep_on
(
&
port
->
in_wait_q
);
if
(
signal_pending
(
current
))
return
-
EINTR
;
local_irq_save
(
flags
);
start
=
(
unsigned
char
*
)
port
->
readp
;
/* cast away volatile */
end
=
(
unsigned
char
*
)
port
->
writep
;
/* cast away volatile */
local_irq_restore
(
flags
);
}
/* Lazy read, never return wrapped data. */
if
(
port
->
full
)
avail
=
port
->
in_buffer_size
;
else
if
(
end
>
start
)
avail
=
end
-
start
;
else
avail
=
port
->
flip
+
port
->
in_buffer_size
-
start
;
count
=
count
>
avail
?
avail
:
count
;
if
(
copy_to_user
(
buf
,
start
,
count
))
return
-
EFAULT
;
/* Disable interrupts while updating readp */
local_irq_save
(
flags
);
port
->
readp
+=
count
;
if
(
port
->
readp
>=
port
->
flip
+
port
->
in_buffer_size
)
/* Wrap? */
port
->
readp
=
port
->
flip
;
port
->
full
=
0
;
local_irq_restore
(
flags
);
DEBUGREAD
(
printk
(
KERN_DEBUG
"r %d
\n
"
,
count
));
return
count
;
}
static
void
send_word
(
struct
sync_port
*
port
)
{
switch
(
IO_EXTRACT
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
port
->
ctrl_data_shadow
))
{
case
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size8bit
):
port
->
out_count
--
;
*
port
->
data_out
=
*
port
->
outp
++
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
break
;
case
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size12bit
):
{
int
data
=
(
*
port
->
outp
++
)
<<
8
;
data
|=
*
port
->
outp
++
;
port
->
out_count
-=
2
;
*
port
->
data_out
=
data
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
break
;
}
case
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size16bit
):
port
->
out_count
-=
2
;
*
port
->
data_out
=
*
(
unsigned
short
*
)
port
->
outp
;
port
->
outp
+=
2
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
break
;
case
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size24bit
):
port
->
out_count
-=
3
;
*
port
->
data_out
=
*
(
unsigned
int
*
)
port
->
outp
;
port
->
outp
+=
3
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
break
;
case
IO_STATE_VALUE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size32bit
):
port
->
out_count
-=
4
;
*
port
->
data_out
=
*
(
unsigned
int
*
)
port
->
outp
;
port
->
outp
+=
4
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
break
;
}
}
static
void
start_dma
(
struct
sync_port
*
port
,
const
char
*
data
,
int
count
)
{
port
->
tr_running
=
1
;
port
->
out_descr
.
hw_len
=
0
;
port
->
out_descr
.
next
=
0
;
port
->
out_descr
.
ctrl
=
d_eol
|
d_eop
;
/* No d_wait to avoid glitches */
port
->
out_descr
.
sw_len
=
count
;
port
->
out_descr
.
buf
=
virt_to_phys
(
data
);
port
->
out_descr
.
status
=
0
;
*
port
->
output_dma_first
=
virt_to_phys
(
&
port
->
out_descr
);
*
port
->
output_dma_cmd
=
IO_STATE
(
R_DMA_CH0_CMD
,
cmd
,
start
);
DEBUGTXINT
(
printk
(
KERN_DEBUG
"dma %08lX c %d
\n
"
,
(
unsigned
long
)
data
,
count
));
}
static
void
start_dma_in
(
struct
sync_port
*
port
)
{
int
i
;
unsigned
long
buf
;
port
->
writep
=
port
->
flip
;
if
(
port
->
writep
>
port
->
flip
+
port
->
in_buffer_size
)
{
panic
(
"Offset too large in sync serial driver
\n
"
);
return
;
}
buf
=
virt_to_phys
(
port
->
in_buffer
);
for
(
i
=
0
;
i
<
NUM_IN_DESCR
;
i
++
)
{
port
->
in_descr
[
i
].
sw_len
=
port
->
inbufchunk
;
port
->
in_descr
[
i
].
ctrl
=
d_int
;
port
->
in_descr
[
i
].
next
=
virt_to_phys
(
&
port
->
in_descr
[
i
+
1
]);
port
->
in_descr
[
i
].
buf
=
buf
;
port
->
in_descr
[
i
].
hw_len
=
0
;
port
->
in_descr
[
i
].
status
=
0
;
port
->
in_descr
[
i
].
fifo_len
=
0
;
buf
+=
port
->
inbufchunk
;
prepare_rx_descriptor
(
&
port
->
in_descr
[
i
]);
}
/* Link the last descriptor to the first */
port
->
in_descr
[
i
-
1
].
next
=
virt_to_phys
(
&
port
->
in_descr
[
0
]);
port
->
in_descr
[
i
-
1
].
ctrl
|=
d_eol
;
port
->
next_rx_desc
=
&
port
->
in_descr
[
0
];
port
->
prev_rx_desc
=
&
port
->
in_descr
[
NUM_IN_DESCR
-
1
];
*
port
->
input_dma_first
=
virt_to_phys
(
port
->
next_rx_desc
);
*
port
->
input_dma_cmd
=
IO_STATE
(
R_DMA_CH0_CMD
,
cmd
,
start
);
}
#ifdef SYNC_SER_DMA
static
irqreturn_t
tr_interrupt
(
int
irq
,
void
*
dev_id
)
{
unsigned
long
ireg
=
*
R_IRQ_MASK2_RD
;
struct
etrax_dma_descr
*
descr
;
unsigned
int
sentl
;
int
handled
=
0
;
int
i
;
for
(
i
=
0
;
i
<
NUMBER_OF_PORTS
;
i
++
)
{
struct
sync_port
*
port
=
&
ports
[
i
];
if
(
!
port
->
enabled
||
!
port
->
use_dma
)
continue
;
/* IRQ active for the port? */
if
(
!
(
ireg
&
(
1
<<
port
->
output_dma_bit
)))
continue
;
handled
=
1
;
/* Clear IRQ */
*
port
->
output_dma_clr_irq
=
IO_STATE
(
R_DMA_CH0_CLR_INTR
,
clr_eop
,
do
)
|
IO_STATE
(
R_DMA_CH0_CLR_INTR
,
clr_descr
,
do
);
descr
=
&
port
->
out_descr
;
if
(
!
(
descr
->
status
&
d_stop
))
sentl
=
descr
->
sw_len
;
else
/* Otherwise find amount of data sent here */
sentl
=
descr
->
hw_len
;
port
->
out_count
-=
sentl
;
port
->
outp
+=
sentl
;
if
(
port
->
outp
>=
port
->
out_buffer
+
OUT_BUFFER_SIZE
)
port
->
outp
=
port
->
out_buffer
;
if
(
port
->
out_count
)
{
int
c
=
port
->
out_buffer
+
OUT_BUFFER_SIZE
-
port
->
outp
;
if
(
c
>
port
->
out_count
)
c
=
port
->
out_count
;
DEBUGTXINT
(
printk
(
KERN_DEBUG
"tx_int DMAWRITE %i %i
\n
"
,
sentl
,
c
));
start_dma
(
port
,
port
->
outp
,
c
);
}
else
{
DEBUGTXINT
(
printk
(
KERN_DEBUG
"tx_int DMA stop %i
\n
"
,
sentl
));
port
->
tr_running
=
0
;
}
/* wake up the waiting process */
wake_up_interruptible
(
&
port
->
out_wait_q
);
}
return
IRQ_RETVAL
(
handled
);
}
/* tr_interrupt */
static
irqreturn_t
rx_interrupt
(
int
irq
,
void
*
dev_id
)
{
unsigned
long
ireg
=
*
R_IRQ_MASK2_RD
;
int
i
;
int
handled
=
0
;
for
(
i
=
0
;
i
<
NUMBER_OF_PORTS
;
i
++
)
{
struct
sync_port
*
port
=
&
ports
[
i
];
if
(
!
port
->
enabled
||
!
port
->
use_dma
)
continue
;
if
(
!
(
ireg
&
(
1
<<
port
->
input_dma_descr_bit
)))
continue
;
/* Descriptor interrupt */
handled
=
1
;
while
(
*
port
->
input_dma_descr
!=
virt_to_phys
(
port
->
next_rx_desc
))
{
if
(
port
->
writep
+
port
->
inbufchunk
>
port
->
flip
+
port
->
in_buffer_size
)
{
int
first_size
=
port
->
flip
+
port
->
in_buffer_size
-
port
->
writep
;
memcpy
(
port
->
writep
,
phys_to_virt
(
port
->
next_rx_desc
->
buf
),
first_size
);
memcpy
(
port
->
flip
,
phys_to_virt
(
port
->
next_rx_desc
->
buf
+
first_size
),
port
->
inbufchunk
-
first_size
);
port
->
writep
=
port
->
flip
+
port
->
inbufchunk
-
first_size
;
}
else
{
memcpy
(
port
->
writep
,
phys_to_virt
(
port
->
next_rx_desc
->
buf
),
port
->
inbufchunk
);
port
->
writep
+=
port
->
inbufchunk
;
if
(
port
->
writep
>=
port
->
flip
+
port
->
in_buffer_size
)
port
->
writep
=
port
->
flip
;
}
if
(
port
->
writep
==
port
->
readp
)
port
->
full
=
1
;
prepare_rx_descriptor
(
port
->
next_rx_desc
);
port
->
next_rx_desc
->
ctrl
|=
d_eol
;
port
->
prev_rx_desc
->
ctrl
&=
~
d_eol
;
port
->
prev_rx_desc
=
phys_to_virt
((
unsigned
)
port
->
next_rx_desc
);
port
->
next_rx_desc
=
phys_to_virt
((
unsigned
)
port
->
next_rx_desc
->
next
);
/* Wake up the waiting process */
wake_up_interruptible
(
&
port
->
in_wait_q
);
*
port
->
input_dma_cmd
=
IO_STATE
(
R_DMA_CH1_CMD
,
cmd
,
restart
);
/* DMA has reached end of descriptor */
*
port
->
input_dma_clr_irq
=
IO_STATE
(
R_DMA_CH0_CLR_INTR
,
clr_descr
,
do
);
}
}
return
IRQ_RETVAL
(
handled
);
}
/* rx_interrupt */
#endif
/* SYNC_SER_DMA */
#ifdef SYNC_SER_MANUAL
static
irqreturn_t
manual_interrupt
(
int
irq
,
void
*
dev_id
)
{
int
i
;
int
handled
=
0
;
for
(
i
=
0
;
i
<
NUMBER_OF_PORTS
;
i
++
)
{
struct
sync_port
*
port
=
&
ports
[
i
];
if
(
!
port
->
enabled
||
port
->
use_dma
)
continue
;
/* Data received? */
if
(
*
R_IRQ_MASK1_RD
&
(
1
<<
port
->
data_avail_bit
))
{
handled
=
1
;
/* Read data */
switch
(
port
->
ctrl_data_shadow
&
IO_MASK
(
R_SYNC_SERIAL1_CTRL
,
wordsize
))
{
case
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size8bit
):
*
port
->
writep
++
=
*
(
volatile
char
*
)
port
->
data_in
;
break
;
case
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size12bit
):
{
int
data
=
*
(
unsigned
short
*
)
port
->
data_in
;
*
port
->
writep
=
(
data
&
0x0ff0
)
>>
4
;
*
(
port
->
writep
+
1
)
=
data
&
0x0f
;
port
->
writep
+=
2
;
break
;
}
case
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size16bit
):
*
(
unsigned
short
*
)
port
->
writep
=
*
(
volatile
unsigned
short
*
)
port
->
data_in
;
port
->
writep
+=
2
;
break
;
case
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size24bit
):
*
(
unsigned
int
*
)
port
->
writep
=
*
port
->
data_in
;
port
->
writep
+=
3
;
break
;
case
IO_STATE
(
R_SYNC_SERIAL1_CTRL
,
wordsize
,
size32bit
):
*
(
unsigned
int
*
)
port
->
writep
=
*
port
->
data_in
;
port
->
writep
+=
4
;
break
;
}
/* Wrap? */
if
(
port
->
writep
>=
port
->
flip
+
port
->
in_buffer_size
)
port
->
writep
=
port
->
flip
;
if
(
port
->
writep
==
port
->
readp
)
{
/* Receive buffer overrun, discard oldest */
port
->
readp
++
;
/* Wrap? */
if
(
port
->
readp
>=
port
->
flip
+
port
->
in_buffer_size
)
port
->
readp
=
port
->
flip
;
}
if
(
sync_data_avail
(
port
)
>=
port
->
inbufchunk
)
{
/* Wake up application */
wake_up_interruptible
(
&
port
->
in_wait_q
);
}
}
/* Transmitter ready? */
if
(
*
R_IRQ_MASK1_RD
&
(
1
<<
port
->
transmitter_ready_bit
))
{
if
(
port
->
out_count
>
0
)
{
/* More data to send */
send_word
(
port
);
}
else
{
/* Transmission finished */
/* Turn off IRQ */
*
R_IRQ_MASK1_CLR
=
1
<<
port
->
transmitter_ready_bit
;
/* Wake up application */
wake_up_interruptible
(
&
port
->
out_wait_q
);
}
}
}
return
IRQ_RETVAL
(
handled
);
}
#endif
module_init
(
etrax_sync_serial_init
);
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