1 /**************************************************
3 * drivers/ifx/serial/ifx_ssc.c
5 * Driver for IFX_SSC serial ports
7 * Copyright (C) 2004 Infineon Technologies AG
8 * Author Michael Schoenenborn (IFX COM TI BT)
11 #define IFX_SSC_DRV_VERSION "0.2.1"
13 **************************************************
15 * This driver was originally based on the INCA-IP driver, but due to
16 * fundamental conceptual drawbacks there has been changed a lot.
18 * Based on INCA-IP driver Copyright (c) 2003 Gary Jennejohn <gj@denx.de>
19 * Based on the VxWorks drivers Copyright (c) 2002, Infineon Technologies.
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37 // ### TO DO: general issues:
39 // - interrupt handling (direct/indirect)
40 // - pin/mux-handling (just overall concept due to project dependency)
41 // - multiple instances capability
42 // - slave functionality
51 #include <linux/config.h>
52 #include <linux/module.h>
53 #include <linux/errno.h>
54 #include <linux/signal.h>
55 #include <linux/sched.h>
56 #include <linux/timer.h>
57 #include <linux/interrupt.h>
58 #include <linux/major.h>
59 #include <linux/string.h>
61 #include <linux/proc_fs.h>
62 #include <linux/fcntl.h>
63 #include <linux/ptrace.h>
65 #include <linux/ioport.h>
66 #include <linux/init.h>
67 #include <linux/delay.h>
68 #include <linux/spinlock.h>
69 #include <linux/slab.h>
70 //#include <linux/poll.h>
72 #include <asm/system.h>
75 #include <asm/uaccess.h>
76 #include <asm/bitops.h>
78 #include <linux/types.h>
79 #include <linux/kernel.h>
80 #include <linux/version.h>
82 #include <asm/amazon/amazon.h>
83 #include <asm/amazon/irq.h>
84 #include <asm/amazon/ifx_ssc_defines.h>
85 #include <asm/amazon/ifx_ssc.h>
87 #ifdef SSC_FRAME_INT_ENABLE
88 #undef SSC_FRAME_INT_ENABLE
96 * Deal with CONFIG_MODVERSIONS
98 #if CONFIG_MODVERSIONS==1
99 # include <linux/modversions.h>
102 MODULE_LICENSE("GPL");
103 MODULE_AUTHOR("Michael Schoenenborn");
104 MODULE_DESCRIPTION("IFX SSC driver");
105 MODULE_SUPPORTED_DEVICE("ifx_ssc");
106 MODULE_PARM(maj
, "i");
107 MODULE_PARM_DESC(maj
, "Major device number");
109 /* allow the user to set the major device number */
114 * This is the per-channel data structure containing pointers, flags
115 * and variables for the port. This driver supports a maximum of PORT_CNT.
116 * isp is allocated in ifx_ssc_init() based on the chip version.
118 static struct ifx_ssc_port
*isp
;
120 /* prototypes for fops */
121 static ssize_t
ifx_ssc_read(struct file
*, char *, size_t, loff_t
*);
122 static ssize_t
ifx_ssc_write(struct file
*, const char *, size_t, loff_t
*);
123 //static unsigned int ifx_ssc_poll(struct file *, struct poll_table_struct *);
124 int ifx_ssc_ioctl(struct inode
*, struct file
*, unsigned int, unsigned long);
125 int ifx_ssc_open(struct inode
*, struct file
*);
126 int ifx_ssc_close(struct inode
*, struct file
*);
128 /* other forward declarations */
129 static unsigned int ifx_ssc_get_kernel_clk(struct ifx_ssc_port
*info
);
130 static void ifx_ssc_rx_int(int, void *, struct pt_regs
*);
131 static void ifx_ssc_tx_int(int, void *, struct pt_regs
*);
132 static void ifx_ssc_err_int(int, void *, struct pt_regs
*);
133 #ifdef SSC_FRAME_INT_ENABLE
134 static void ifx_ssc_frm_int(int, void *, struct pt_regs
*);
136 static void tx_int(struct ifx_ssc_port
*);
137 static int ifx_ssc1_read_proc(char *, char **, off_t
, int, int *, void *);
138 static void ifx_gpio_init(void);
139 /************************************************************************
140 * Function declaration
141 ************************************************************************/
143 extern unsigned int amazon_get_fpi_hz(void);
144 extern void disable_amazon_irq(unsigned int irq_nr
);
145 extern void enable_amazon_irq(unsigned int irq_nr
);
146 extern void mask_and_ack_amazon_irq(unsigned int irq_nr
);
149 /*****************************************************************/
151 int (*request
)(unsigned int irq
,
152 void (*handler
)(int, void *, struct pt_regs
*),
153 unsigned long irqflags
,
154 const char * devname
,
156 void (*free
)(unsigned int irq
, void *dev_id
);
157 void (*enable
)(unsigned int irq
);
158 void (*disable
)(unsigned int irq
);
159 void (*clear
)(unsigned int irq
);
162 static ifx_int_wrapper_t ifx_int_wrapper
= {
163 request
: request_irq
, // IM action: enable int
164 free
: free_irq
, // IM action: disable int
165 enable
: enable_amazon_irq
,
166 disable
: disable_amazon_irq
,
167 clear
: mask_and_ack_amazon_irq
,
172 static struct file_operations ifx_ssc_fops
= {
174 read
: ifx_ssc_read
, /* read */
175 write
: ifx_ssc_write
, /* write */
176 // poll: ifx_ssc_poll, /* poll */
177 ioctl
: ifx_ssc_ioctl
, /* ioctl */
178 open
: ifx_ssc_open
, /* open */
179 release
: ifx_ssc_close
, /* release */
183 static inline unsigned int ifx_ssc_get_kernel_clk(struct ifx_ssc_port
*info
)
184 { // ATTENTION: This function assumes that the CLC register is set with the
185 // appropriate value for RMC.
188 rmc
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_CLC
) &
189 IFX_CLC_RUN_DIVIDER_MASK
) >> IFX_CLC_RUN_DIVIDER_OFFSET
;
191 printk("ifx_ssc_get_kernel_clk rmc==0 \n");
194 return (amazon_get_fpi_hz() / rmc
);
198 #ifdef IFX_SSC_INT_USE_BH
200 * This routine is used by the interrupt handler to schedule
201 * processing in the software interrupt portion of the driver
202 * (also known as the "bottom half"). This can be called any
203 * number of times for any channel without harm.
206 ifx_ssc_sched_event(struct ifx_ssc_port
*info
, int event
)
208 info
->event
|= 1 << event
; /* remember what kind of event and who */
209 queue_task(&info
->tqueue
, &tq_cyclades
); /* it belongs to */
210 mark_bh(CYCLADES_BH
); /* then trigger event */
211 } /* ifx_ssc_sched_event */
215 * This routine is used to handle the "bottom half" processing for the
216 * serial driver, known also the "software interrupt" processing.
217 * This processing is done at the kernel interrupt level, after the
218 * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
219 * is where time-consuming activities which can not be done in the
220 * interrupt driver proper are done; the interrupt driver schedules
221 * them using ifx_ssc_sched_event(), and they get done here.
223 * This is done through one level of indirection--the task queue.
224 * When a hardware interrupt service routine wants service by the
225 * driver's bottom half, it enqueues the appropriate tq_struct (one
226 * per port) to the tq_cyclades work queue and sets a request flag
227 * via mark_bh for processing that queue. When the time is right,
228 * do_ifx_ssc_bh is called (because of the mark_bh) and it requests
229 * that the work queue be processed.
231 * Although this may seem unwieldy, it gives the system a way to
232 * pass an argument (in this case the pointer to the ifx_ssc_port
233 * structure) to the bottom half of the driver. Previous kernels
234 * had to poll every port to see if that port needed servicing.
239 run_task_queue(&tq_cyclades
);
240 } /* do_ifx_ssc_bh */
243 do_softint(void *private_
)
245 struct ifx_ssc_port
*info
= (struct ifx_ssc_port
*) private_
;
247 if (test_and_clear_bit(Cy_EVENT_HANGUP
, &info
->event
)) {
248 wake_up_interruptible(&info
->open_wait
);
249 info
->flags
&= ~(ASYNC_NORMAL_ACTIVE
|
250 ASYNC_CALLOUT_ACTIVE
);
252 if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP
, &info
->event
)) {
253 wake_up_interruptible(&info
->open_wait
);
255 if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP
, &info
->event
)) {
256 wake_up_interruptible(&info
->delta_msr_wait
);
258 if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP
, &info
->event
)) {
259 wake_up_interruptible(&tty
->write_wait
);
262 if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP
, &info
->event
)) {
263 wake_up_interruptible(&info
->shutdown_wait
);
267 #endif /* IFX_SSC_INT_USE_BH */
271 rx_int(struct ifx_ssc_port
*info
)
273 int fifo_fill_lev
, bytes_in_buf
, i
;
274 unsigned long tmp_val
;
275 unsigned long *tmp_ptr
;
276 unsigned int rx_valid_cnt
;
277 /* number of words waiting in the RX FIFO */
278 fifo_fill_lev
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+
280 IFX_SSC_FSTAT_RECEIVED_WORDS_MASK
) >>
281 IFX_SSC_FSTAT_RECEIVED_WORDS_OFFSET
;
282 // Note: There are always 32 bits in a fifo-entry except for the last
283 // word of a contigous transfer block and except for not in rx-only
284 // mode and CON.ENBV set. But for this case it should be a convention
285 // in software which helps:
286 // In tx or rx/tx mode all transfers from the buffer to the FIFO are
287 // 32-bit wide, except for the last three bytes, which could be a
288 // combination of 16- and 8-bit access.
289 // => The whole block is received as 32-bit words as a contigous stream,
290 // even if there was a gap in tx which has the fifo run out of data!
291 // Just the last fifo entry *may* be partially filled (0, 1, 2 or 3 bytes)!
293 /* free space in the RX buffer */
294 bytes_in_buf
= info
->rxbuf_end
- info
->rxbuf_ptr
;
295 // transfer with 32 bits per entry
296 while ((bytes_in_buf
>= 4) && (fifo_fill_lev
> 0)) {
297 tmp_ptr
= (unsigned long *)info
->rxbuf_ptr
;
298 *tmp_ptr
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RB
);
299 info
->rxbuf_ptr
+= 4;
300 info
->stats
.rxBytes
+= 4;
303 } // while ((bytes_in_buf >= 4) && (fifo_fill_lev > 0))
304 // now do the rest as mentioned in STATE.RXBV
305 while ((bytes_in_buf
> 0) && (fifo_fill_lev
> 0)) {
306 rx_valid_cnt
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
) &
307 IFX_SSC_STATE_RX_BYTE_VALID_MASK
) >>
308 IFX_SSC_STATE_RX_BYTE_VALID_OFFSET
;
309 if (rx_valid_cnt
== 0) break;
310 if (rx_valid_cnt
> bytes_in_buf
) {
311 // ### TO DO: warning message: not block aligned data, other data
312 // in this entry will be lost
313 rx_valid_cnt
= bytes_in_buf
;
315 tmp_val
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RB
);
317 for (i
=0; i
<rx_valid_cnt
; i
++) {
318 *info
->rxbuf_ptr
= (tmp_val
>> ( 8 * (rx_valid_cnt
- i
-1))) & 0xff;
320 *info->rxbuf_ptr = tmp_val & 0xff;
328 info
->stats
.rxBytes
+= rx_valid_cnt
;
329 } // while ((bytes_in_buf > 0) && (fifo_fill_lev > 0))
331 // check if transfer is complete
332 if (info
->rxbuf_ptr
>= info
->rxbuf_end
) {
333 ifx_int_wrapper
.disable(info
->rxirq
);
334 /* wakeup any processes waiting in read() */
335 wake_up_interruptible(&info
->rwait
);
337 //wake_up_interruptible(&info->pwait);
338 } else if ((info
->opts
.modeRxTx
== IFX_SSC_MODE_RX
) &&
339 (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RXCNT
) == 0)) {
340 // if buffer not filled completely and rx request done initiate new transfer
342 if (info->rxbuf_end - info->rxbuf_ptr < 65536)
344 if (info
->rxbuf_end
- info
->rxbuf_ptr
< IFX_SSC_RXREQ_BLOCK_SIZE
)
345 WRITE_PERIPHERAL_REGISTER((info
->rxbuf_end
- info
->rxbuf_ptr
) <<
346 IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
347 info
->mapbase
+ IFX_SSC_RXREQ
);
349 WRITE_PERIPHERAL_REGISTER(IFX_SSC_RXREQ_BLOCK_SIZE
<< IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
350 info
->mapbase
+ IFX_SSC_RXREQ
);
355 tx_int(struct ifx_ssc_port
*info
)
358 int fifo_space
, fill
, i
;
359 fifo_space
= ((READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_ID
) &
360 IFX_SSC_PERID_TXFS_MASK
) >> IFX_SSC_PERID_TXFS_OFFSET
) -
361 ((READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_FSTAT
) &
362 IFX_SSC_FSTAT_TRANSMIT_WORDS_MASK
) >>
363 IFX_SSC_FSTAT_TRANSMIT_WORDS_OFFSET
);
368 fill
= info
->txbuf_end
- info
->txbuf_ptr
;
370 if (fill
> fifo_space
* 4)
371 fill
= fifo_space
* 4;
373 for (i
= 0; i
< fill
/ 4; i
++) {
374 // at first 32 bit access
375 WRITE_PERIPHERAL_REGISTER(*(UINT32
*)info
->txbuf_ptr
, info
->mapbase
+ IFX_SSC_TB
);
376 info
->txbuf_ptr
+= 4;
379 fifo_space
-= fill
/ 4;
380 info
->stats
.txBytes
+= fill
& ~0x3;
382 if ((fifo_space
> 0) & (fill
> 1)) {
383 // trailing 16 bit access
384 WRITE_PERIPHERAL_REGISTER_16(*(UINT16
*)info
->txbuf_ptr
, info
->mapbase
+ IFX_SSC_TB
);
385 info
->txbuf_ptr
+= 2;
386 info
->stats
.txBytes
+= 2;
388 /* added by bingtao */
391 if ((fifo_space
> 0) & (fill
> 0)) {
392 // trailing 8 bit access
393 WRITE_PERIPHERAL_REGISTER_8(*(UINT8
*)info
->txbuf_ptr
, info
->mapbase
+ IFX_SSC_TB
);
395 info
->stats
.txBytes
++;
401 // check if transmission complete
402 if (info
->txbuf_ptr
>= info
->txbuf_end
) {
403 ifx_int_wrapper
.disable(info
->txirq
);
406 /* wake up any process waiting in poll() */
407 //wake_up_interruptible(&info->pwait);
413 ifx_ssc_rx_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
415 struct ifx_ssc_port
*info
= (struct ifx_ssc_port
*)dev_id
;
416 //WRITE_PERIPHERAL_REGISTER(IFX_SSC_R_BIT, info->mapbase + IFX_SSC_IRN_CR);
421 ifx_ssc_tx_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
423 struct ifx_ssc_port
*info
= (struct ifx_ssc_port
*)dev_id
;
424 //WRITE_PERIPHERAL_REGISTER(IFX_SSC_T_BIT, info->mapbase + IFX_SSC_IRN_CR);
429 ifx_ssc_err_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
431 struct ifx_ssc_port
*info
= (struct ifx_ssc_port
*)dev_id
;
433 unsigned int write_back
= 0;
437 local_irq_save(flags
);
438 state
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
);
440 if ((state
& IFX_SSC_STATE_RX_UFL
) != 0) {
441 info
->stats
.rxUnErr
++;
442 write_back
|= IFX_SSC_WHBSTATE_CLR_RX_UFL_ERROR
;
444 if ((state
& IFX_SSC_STATE_RX_OFL
) != 0) {
445 info
->stats
.rxOvErr
++;
446 write_back
|= IFX_SSC_WHBSTATE_CLR_RX_OFL_ERROR
;
448 if ((state
& IFX_SSC_STATE_TX_OFL
) != 0) {
449 info
->stats
.txOvErr
++;
450 write_back
|= IFX_SSC_WHBSTATE_CLR_TX_OFL_ERROR
;
452 if ((state
& IFX_SSC_STATE_TX_UFL
) != 0) {
453 info
->stats
.txUnErr
++;
454 write_back
|= IFX_SSC_WHBSTATE_CLR_TX_UFL_ERROR
;
456 // if ((state & IFX_SSC_STATE_ABORT_ERR) != 0) {
457 // info->stats.abortErr++;
458 // write_back |= IFX_SSC_WHBSTATE_CLR_ABORT_ERROR;
460 if ((state
& IFX_SSC_STATE_MODE_ERR
) != 0) {
461 info
->stats
.modeErr
++;
462 write_back
|= IFX_SSC_WHBSTATE_CLR_MODE_ERROR
;
466 WRITE_PERIPHERAL_REGISTER(write_back
,
467 info
->mapbase
+ IFX_SSC_WHBSTATE
);
469 local_irq_restore(flags
);
472 #ifdef SSC_FRAME_INT_ENABLE
474 ifx_ssc_frm_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
476 // ### TO DO: wake up framing wait-queue in conjunction with batch execution
481 ifx_ssc_abort(struct ifx_ssc_port
*info
)
486 local_irq_save(flags
);
489 ifx_int_wrapper
.disable(info
->rxirq
);
490 ifx_int_wrapper
.disable(info
->txirq
);
491 ifx_int_wrapper
.disable(info
->errirq
);
493 ifx_int_wrapper.disable(info->frmirq);
495 local_irq_restore(flags
);
497 // disable SSC (also aborts a receive request!)
498 // ### TO DO: Perhaps it's better to abort after the receiption of a
499 // complete word. The disable cuts the transmission immediatly and
500 // releases the chip selects. This could result in unpredictable
501 // behavior of connected external devices!
502 enabled
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
)
503 & IFX_SSC_STATE_IS_ENABLED
) != 0;
504 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE
,
505 info
->mapbase
+ IFX_SSC_WHBSTATE
);
509 WRITE_PERIPHERAL_REGISTER(IFX_SSC_XFCON_FIFO_FLUSH
,
510 info
->mapbase
+ IFX_SSC_TXFCON
);
511 WRITE_PERIPHERAL_REGISTER(IFX_SSC_XFCON_FIFO_FLUSH
,
512 info
->mapbase
+ IFX_SSC_RXFCON
);
515 if (info
->txbuf
!= NULL
) {
520 // wakeup read process
521 if (info
->rxbuf
!= NULL
)
522 wake_up_interruptible(&info
->rwait
);
524 // clear pending int's
525 ifx_int_wrapper
.clear(info
->rxirq
);
526 ifx_int_wrapper
.clear(info
->txirq
);
527 ifx_int_wrapper
.clear(info
->errirq
);
529 ifx_int_wrapper.clear(info->frmirq);
533 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ALL_ERROR
,
534 info
->mapbase
+ IFX_SSC_WHBSTATE
);
536 //printk("IFX SSC%d: Transmission aborted\n", info->port_nr);
539 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE
,
540 info
->mapbase
+ IFX_SSC_WHBSTATE
);
546 * This routine is called whenever a port is opened. It enforces
547 * exclusive opening of a port and enables interrupts, etc.
550 ifx_ssc_open(struct inode
*inode
, struct file
* filp
)
552 struct ifx_ssc_port
*info
;
556 if ((inode
== (struct inode
*)0) || (inode
== (struct inode
*)1)) {
561 line
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
562 filp
->f_op
= &ifx_ssc_fops
;
565 /* don't open more minor devices than we can support */
566 if (line
< 0 || line
>= PORT_CNT
)
572 if (info
->port_is_open
!= 0)
574 info
->port_is_open
++;
576 ifx_int_wrapper
.disable(info
->rxirq
);
577 ifx_int_wrapper
.disable(info
->txirq
);
578 ifx_int_wrapper
.disable(info
->errirq
);
580 ifx_int_wrapper.disable(info->frmirq);
583 /* Flush and enable TX/RX FIFO */
584 WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_TXFIFO_FL
<<
585 IFX_SSC_XFCON_ITL_OFFSET
) |
586 IFX_SSC_XFCON_FIFO_FLUSH
|
587 IFX_SSC_XFCON_FIFO_ENABLE
,
588 info
->mapbase
+ IFX_SSC_TXFCON
);
589 WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_RXFIFO_FL
<<
590 IFX_SSC_XFCON_ITL_OFFSET
) |
591 IFX_SSC_XFCON_FIFO_FLUSH
|
592 IFX_SSC_XFCON_FIFO_ENABLE
,
593 info
->mapbase
+ IFX_SSC_RXFCON
);
596 /* logically flush the software FIFOs */
600 /* clear all error bits */
601 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ALL_ERROR
,
602 info
->mapbase
+ IFX_SSC_WHBSTATE
);
604 // clear pending interrupts
605 ifx_int_wrapper
.clear(info
->rxirq
);
606 ifx_int_wrapper
.clear(info
->txirq
);
607 ifx_int_wrapper
.clear(info
->errirq
);
609 ifx_int_wrapper.clear(info->frmirq);
613 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE
,
614 info
->mapbase
+ IFX_SSC_WHBSTATE
);
620 EXPORT_SYMBOL(ifx_ssc_open
);
623 * This routine is called when a particular device is closed.
626 ifx_ssc_close(struct inode
*inode
, struct file
*filp
)
628 struct ifx_ssc_port
*info
;
631 if ((inode
== (struct inode
*)0) || (inode
== (struct inode
*)1))
634 idx
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
636 if (idx
< 0 || idx
>= PORT_CNT
)
644 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE
,
645 info
->mapbase
+ IFX_SSC_WHBSTATE
);
647 // call abort function to disable int's, flush fifos...
650 info
->port_is_open
--;
654 } /* ifx_ssc_close */
655 EXPORT_SYMBOL(ifx_ssc_close
);
657 /* added by bingtao */
658 /* helper routine to handle reads from the kernel or user-space */
659 /* info->rxbuf : never kfree and contains valid data */
660 /* should be points to NULL after copying data !!! */
662 ifx_ssc_read_helper_poll(struct ifx_ssc_port
*info
, char *buf
, size_t len
,
668 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_TX
)
670 local_irq_save(flags
);
671 info
->rxbuf_ptr
= info
->rxbuf
;
672 info
->rxbuf_end
= info
->rxbuf
+ len
;
673 local_irq_restore(flags
);
674 /* Vinetic driver always works in IFX_SSC_MODE_RXTX */
675 /* TXRX in poll mode */
676 while (info
->rxbuf_ptr
< info
->rxbuf_end
){
677 /* This is the key point, if you don't check this condition
678 kfree (NULL) will happen
679 because tx only need write into FIFO, it's much fast than rx
680 So when rx still waiting , tx already finish and release buf
682 if (info
->txbuf_ptr
< info
->txbuf_end
) {
689 ret_val
= info
->rxbuf_ptr
- info
->rxbuf
;
691 } // ifx_ssc_read_helper_poll
693 /* helper routine to handle reads from the kernel or user-space */
694 /* info->rx_buf : never kfree and contains valid data */
695 /* should be points to NULL after copying data !!! */
697 ifx_ssc_read_helper(struct ifx_ssc_port
*info
, char *buf
, size_t len
,
702 DECLARE_WAITQUEUE(wait
, current
);
704 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_TX
)
706 local_irq_save(flags
);
707 info
->rxbuf_ptr
= info
->rxbuf
;
708 info
->rxbuf_end
= info
->rxbuf
+ len
;
709 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_RXTX
) {
710 if ((info
->txbuf
== NULL
) ||
711 (info
->txbuf
!= info
->txbuf_ptr
) ||
712 (info
->txbuf_end
!= len
+ info
->txbuf
)) {
713 local_irq_restore(flags
);
714 printk("IFX SSC - %s: write must be called before calling "
715 "read in combined RX/TX!\n", __FUNCTION__
);
718 local_irq_restore(flags
);
719 /* should enable tx, right?*/
721 if (info
->txbuf_ptr
< info
->txbuf_end
){
722 ifx_int_wrapper
.enable(info
->txirq
);
725 ifx_int_wrapper
.enable(info
->rxirq
);
727 local_irq_restore(flags
);
728 if (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RXCNT
) &
729 IFX_SSC_RXCNT_TODO_MASK
)
731 ifx_int_wrapper
.enable(info
->rxirq
);
732 // rx request limited to ' bytes
736 if (len
< IFX_SSC_RXREQ_BLOCK_SIZE
)
737 WRITE_PERIPHERAL_REGISTER(len
<< IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
738 info
->mapbase
+ IFX_SSC_RXREQ
);
740 WRITE_PERIPHERAL_REGISTER(IFX_SSC_RXREQ_BLOCK_SIZE
<< IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
741 info
->mapbase
+ IFX_SSC_RXREQ
);
744 __add_wait_queue(&info
->rwait
, &wait
);
745 set_current_state(TASK_INTERRUPTIBLE
);
746 // wakeup done in rx_int
749 local_irq_save(flags
);
750 if (info
->rxbuf_ptr
>= info
->rxbuf_end
)
752 local_irq_restore(flags
);
754 // if (filp->f_flags & O_NONBLOCK)
759 if (signal_pending(current
)) {
760 ret_val
= -ERESTARTSYS
;
766 ret_val
= info
->rxbuf_ptr
- info
->rxbuf
; // should be equal to len
767 local_irq_restore(flags
);
770 current
->state
= TASK_RUNNING
;
771 __remove_wait_queue(&info
->rwait
, &wait
);
773 } // ifx_ssc_read_helper
777 /* helper routine to handle reads from the kernel or user-space */
778 /* appropriate in interrupt context */
780 ifx_ssc_read_helper(struct ifx_ssc_port
*info
, char *buf
, size_t len
,
785 DECLARE_WAITQUEUE(wait
, current
);
787 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_TX
)
789 local_irq_save(flags
);
790 info
->rxbuf_ptr
= info
->rxbuf
;
791 info
->rxbuf_end
= info
->rxbuf
+ len
;
792 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_RXTX
) {
793 if ((info
->txbuf
== NULL
) ||
794 (info
->txbuf
!= info
->txbuf_ptr
) ||
795 (info
->txbuf_end
!= len
+ info
->txbuf
)) {
796 local_irq_restore(flags
);
797 printk("IFX SSC - %s: write must be called before calling "
798 "read in combined RX/TX!\n", __FUNCTION__
);
801 local_irq_restore(flags
);
802 /* should enable tx, right?*/
805 if (info
->txbuf_ptr
< info
->txbuf_end
){
806 ifx_int_wrapper
.enable(info
->txirq
);
808 ifx_int_wrapper
.enable(info
->rxirq
);
811 local_irq_restore(flags
);
812 if (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RXCNT
) &
813 IFX_SSC_RXCNT_TODO_MASK
)
816 ifx_int_wrapper
.enable(info
->rxirq
);
819 if (len
< IFX_SSC_RXREQ_BLOCK_SIZE
)
820 WRITE_PERIPHERAL_REGISTER(len
<< IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
821 info
->mapbase
+ IFX_SSC_RXREQ
);
823 WRITE_PERIPHERAL_REGISTER(IFX_SSC_RXREQ_BLOCK_SIZE
<< IFX_SSC_RXREQ_RXCOUNT_OFFSET
,
824 info
->mapbase
+ IFX_SSC_RXREQ
);
829 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_RXTX
) {
833 if (info
->rxbuf_ptr
>= info
->rxbuf_end
)
836 ret_val
= info
->rxbuf_ptr
- info
->rxbuf
;
838 __add_wait_queue(&info
->rwait
, &wait
);
839 set_current_state(TASK_INTERRUPTIBLE
);
840 // wakeup done in rx_int
843 local_irq_save(flags
);
844 if (info
->rxbuf_ptr
>= info
->rxbuf_end
)
846 local_irq_restore(flags
);
848 if (signal_pending(current
)) {
849 ret_val
= -ERESTARTSYS
;
855 ret_val
= info
->rxbuf_ptr
- info
->rxbuf
; // should be equal to len
856 local_irq_restore(flags
);
859 current
->state
= TASK_RUNNING
;
860 __remove_wait_queue(&info
->rwait
, &wait
);
863 } // ifx_ssc_read_helper
866 /* helper routine to handle writes to the kernel or user-space */
867 /* info->txbuf has two cases:
868 * 1) return value < 0 (-EFAULT), not touched at all
869 * 2) kfree and points to NULL in interrupt routine (but maybe later )
872 ifx_ssc_write_helper(struct ifx_ssc_port
*info
, const char *buf
,
873 size_t len
, int from_kernel
)
875 // check if in tx or tx/rx mode
876 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_RX
)
879 info
->txbuf_ptr
= info
->txbuf
;
880 info
->txbuf_end
= len
+ info
->txbuf
;
881 /* start the transmission (not in rx/tx, see read helper) */
882 if (info
->opts
.modeRxTx
== IFX_SSC_MODE_TX
) {
884 if (info
->txbuf_ptr
< info
->txbuf_end
){
885 ifx_int_wrapper
.enable(info
->txirq
);
888 //local_irq_restore(flags);
893 * kernel interfaces for read and write.
894 * The caller must set port to: n for SSC<m> with n=m-1 (e.g. n=0 for SSC1)
897 ifx_ssc_kread(int port
, char *kbuf
, size_t len
)
899 struct ifx_ssc_port
*info
;
902 if (port
< 0 || port
>= PORT_CNT
)
910 // check if reception in progress
911 if (info
->rxbuf
!= NULL
){
912 printk("SSC device busy\n");
917 if (info
->rxbuf
== NULL
){
918 printk("SSC device error\n");
922 /* changed by bingtao */
923 /* change by TaiCheng */
926 ret_val
= ifx_ssc_read_helper(info
, kbuf
, len
, 1);
928 ret_val
= ifx_ssc_read_helper_poll(info
, kbuf
, len
, 1);
932 // ### TO DO: perhaps warn if ret_val != len
933 ifx_int_wrapper
.disable(info
->rxirq
);
937 EXPORT_SYMBOL(ifx_ssc_kread
);
940 ifx_ssc_kwrite(int port
, const char *kbuf
, size_t len
)
942 struct ifx_ssc_port
*info
;
945 if (port
< 0 || port
>= PORT_CNT
)
953 // check if transmission in progress
954 if (info
->txbuf
!= NULL
)
956 info
->txbuf
= (char *)kbuf
;
958 ret_val
= ifx_ssc_write_helper(info
, info
->txbuf
, len
, 1);
964 EXPORT_SYMBOL(ifx_ssc_kwrite
);
968 * user interfaces to read and write
971 ifx_ssc_read(struct file
*filp
, char *ubuf
, size_t len
, loff_t
*off
)
975 struct ifx_ssc_port
*info
;
981 idx
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
984 // check if reception in progress
985 if (info
->rxbuf
!= NULL
)
988 info
->rxbuf
= kmalloc(len
+ 3, GFP_KERNEL
);
989 if (info
->rxbuf
== NULL
)
992 ret_val
= ifx_ssc_read_helper(info
, info
->rxbuf
, len
, 0);
993 // ### TO DO: perhaps warn if ret_val != len
994 if (copy_to_user((void*)ubuf
, info
->rxbuf
, ret_val
) != 0)
997 ifx_int_wrapper
.disable(info
->rxirq
);
1005 * As many bytes as we have free space for are copied from the user
1006 * into txbuf and the actual byte count is returned. The transmission is
1007 * always kicked off by calling the appropriate TX routine.
1010 ifx_ssc_write(struct file
*filp
, const char *ubuf
, size_t len
, loff_t
*off
)
1013 struct ifx_ssc_port
*info
;
1019 idx
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
1022 // check if transmission in progress
1023 if (info
->txbuf
!= NULL
)
1026 info
->txbuf
= kmalloc(len
+ 3, GFP_KERNEL
);
1027 if (info
->txbuf
== NULL
)
1030 ret_val
= copy_from_user(info
->txbuf
, ubuf
, len
);
1032 ret_val
= ifx_ssc_write_helper(info
, info
->txbuf
, len
, 0);
1036 kfree(info
->txbuf
); // otherwise will be done in ISR
1040 } /* ifx_ssc_write */
1044 * ------------------------------------------------------------
1045 * ifx_ssc_ioctl() and friends
1046 * ------------------------------------------------------------
1049 /*-----------------------------------------------------------------------------
1050 FUNC-NAME : ifx_ssc_frm_status_get
1051 LONG-NAME : framing status get
1052 PURPOSE : Get the actual status of the framing.
1054 PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
1056 RESULT : pointer to a structure ifx_ssc_frm_status which holds busy and
1059 REMARKS : Returns a register value independent of framing is enabled or
1060 not! Changes structure inside of info, so the return value isn't
1061 needed at all, but could be used for simple access.
1062 -----------------------------------------------------------------------------*/
1063 static struct ifx_ssc_frm_status
*
1064 ifx_ssc_frm_status_get(struct ifx_ssc_port
*info
)
1068 tmp
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_SFSTAT
);
1069 info
->frm_status
.DataBusy
= (tmp
& IFX_SSC_SFSTAT_IN_DATA
) > 0;
1070 info
->frm_status
.PauseBusy
= (tmp
& IFX_SSC_SFSTAT_IN_PAUSE
) > 0;
1071 info
->frm_status
.DataCount
= (tmp
& IFX_SSC_SFSTAT_DATA_COUNT_MASK
)
1072 >> IFX_SSC_SFSTAT_DATA_COUNT_OFFSET
;
1073 info
->frm_status
.PauseCount
= (tmp
& IFX_SSC_SFSTAT_PAUSE_COUNT_MASK
)
1074 >> IFX_SSC_SFSTAT_PAUSE_COUNT_OFFSET
;
1075 tmp
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_SFCON
);
1076 info
->frm_status
.EnIntAfterData
=
1077 (tmp
& IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE
) > 0;
1078 info
->frm_status
.EnIntAfterPause
=
1079 (tmp
& IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE
) > 0;
1080 return (&info
->frm_status
);
1081 } // ifx_ssc_frm_status_get
1084 /*-----------------------------------------------------------------------------
1085 FUNC-NAME : ifx_ssc_frm_control_get
1086 LONG-NAME : framing control get
1087 PURPOSE : Get the actual control values of the framing.
1089 PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
1091 RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
1092 and count reload values.
1094 REMARKS : Changes structure inside of info, so the return value isn't
1095 needed at all, but could be used for simple access.
1096 -----------------------------------------------------------------------------*/
1097 static struct ifx_ssc_frm_opts
*
1098 ifx_ssc_frm_control_get(struct ifx_ssc_port
*info
)
1102 tmp
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_SFCON
);
1103 info
->frm_opts
.FrameEnable
= (tmp
& IFX_SSC_SFCON_SF_ENABLE
) > 0;
1104 info
->frm_opts
.DataLength
= (tmp
& IFX_SSC_SFCON_DATA_LENGTH_MASK
)
1105 >> IFX_SSC_SFCON_DATA_LENGTH_OFFSET
;
1106 info
->frm_opts
.PauseLength
= (tmp
& IFX_SSC_SFCON_PAUSE_LENGTH_MASK
)
1107 >> IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET
;
1108 info
->frm_opts
.IdleData
= (tmp
& IFX_SSC_SFCON_PAUSE_DATA_MASK
)
1109 >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET
;
1110 info
->frm_opts
.IdleClock
= (tmp
& IFX_SSC_SFCON_PAUSE_CLOCK_MASK
)
1111 >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET
;
1112 info
->frm_opts
.StopAfterPause
=
1113 (tmp
& IFX_SSC_SFCON_STOP_AFTER_PAUSE
) > 0;
1114 return (&info
->frm_opts
);
1115 } // ifx_ssc_frm_control_get
1118 /*-----------------------------------------------------------------------------
1119 FUNC-NAME : ifx_ssc_frm_control_set
1120 LONG-NAME : framing control set
1121 PURPOSE : Set the actual control values of the framing.
1123 PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
1125 RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
1126 and count reload values.
1129 -----------------------------------------------------------------------------*/
1131 ifx_ssc_frm_control_set(struct ifx_ssc_port
*info
)
1136 if ((info
->frm_opts
.DataLength
> IFX_SSC_SFCON_DATA_LENGTH_MAX
) ||
1137 (info
->frm_opts
.DataLength
< 1) ||
1138 (info
->frm_opts
.PauseLength
> IFX_SSC_SFCON_PAUSE_LENGTH_MAX
) ||
1139 (info
->frm_opts
.PauseLength
< 1) ||
1140 ((info
->frm_opts
.IdleData
& ~(IFX_SSC_SFCON_PAUSE_DATA_MASK
>>
1141 IFX_SSC_SFCON_PAUSE_DATA_OFFSET
)) != 0 ) ||
1142 ((info
->frm_opts
.IdleClock
& ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK
>>
1143 IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET
)) != 0 ))
1146 // read interrupt bits (they're not changed here)
1147 tmp
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_SFCON
) &
1148 (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE
|
1149 IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE
);
1151 // set all values with respect to it's bit position (for data and pause
1153 tmp
= (info
->frm_opts
.DataLength
- 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET
;
1154 tmp
|= (info
->frm_opts
.PauseLength
- 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET
;
1155 tmp
|= info
->frm_opts
.IdleData
<< IFX_SSC_SFCON_PAUSE_DATA_OFFSET
;
1156 tmp
|= info
->frm_opts
.IdleClock
<< IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET
;
1157 tmp
|= info
->frm_opts
.FrameEnable
* IFX_SSC_SFCON_SF_ENABLE
;
1158 tmp
|= info
->frm_opts
.StopAfterPause
* IFX_SSC_SFCON_STOP_AFTER_PAUSE
;
1160 WRITE_PERIPHERAL_REGISTER(tmp
, info
->mapbase
+ IFX_SSC_SFCON
);
1163 } // ifx_ssc_frm_control_set
1166 /*-----------------------------------------------------------------------------
1167 FUNC-NAME : ifx_ssc_rxtx_mode_set
1168 LONG-NAME : rxtx mode set
1169 PURPOSE : Set the transmission mode.
1171 PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
1173 RESULT : Returns error code
1175 REMARKS : Assumes that SSC not used (SSC disabled, device not opened yet
1177 -----------------------------------------------------------------------------*/
1179 ifx_ssc_rxtx_mode_set(struct ifx_ssc_port
*info
, unsigned int val
)
1184 if (!(info
) || (val
& ~(IFX_SSC_MODE_MASK
)))
1186 /*check BUSY and RXCNT*/
1187 if ( READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
) & IFX_SSC_STATE_BUSY
1188 ||READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_RXCNT
) & IFX_SSC_RXCNT_TODO_MASK
)
1191 tmp
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_CON
) &
1192 ~(IFX_SSC_CON_RX_OFF
| IFX_SSC_CON_TX_OFF
)) | (val
);
1193 WRITE_PERIPHERAL_REGISTER(tmp
, info
->mapbase
+ IFX_SSC_CON
);
1194 info
->opts
.modeRxTx
= val
;
1196 printk(KERN_DEBUG "IFX SSC%d: Setting mode to %s%s\n",
1198 ((val & IFX_SSC_CON_RX_OFF) == 0) ? "rx ":"",
1199 ((val & IFX_SSC_CON_TX_OFF) == 0) ? "tx":"");
1202 } // ifx_ssc_rxtx_mode_set
1204 void ifx_gpio_init(void)
1207 /* set gpio pin p0.10(SPI_DIN) p0.11(SPI_DOUT) p0.12(SPI_CLK) p0.13(SPI_CS2) direction */
1208 temp
= *(AMAZON_GPIO_P0_DIR
) ;
1211 *(AMAZON_GPIO_P0_DIR
) = temp
;
1212 /* set port 0 alternate select register 0 */
1213 temp
= *(AMAZON_GPIO_P0_ALTSEL0
) ;
1216 *(AMAZON_GPIO_P0_ALTSEL0
) = temp
;
1218 /* set port 0 alternate select register 1 */
1219 temp
= *(AMAZON_GPIO_P0_ALTSEL1
) ;
1222 *(AMAZON_GPIO_P0_ALTSEL1
) = temp
;
1224 /* set port 0 open drain mode register */
1225 temp
= *(AMAZON_GPIO_P0_OD
);
1226 temp
|= 0x00003800; /* set output pin normal mode */
1227 *(AMAZON_GPIO_P0_OD
)= temp
;
1231 * This routine intializes the SSC appropriately depending
1232 * on slave/master and full-/half-duplex mode.
1233 * It assumes that the SSC is disabled and the fifo's and buffers
1234 * are flushes later on.
1237 ifx_ssc_sethwopts(struct ifx_ssc_port
*info
)
1239 unsigned long flags
, bits
;
1240 struct ifx_ssc_hwopts
*opts
= &info
->opts
;
1243 if ((opts
->dataWidth
< IFX_SSC_MIN_DATA_WIDTH
) ||
1244 (opts
->dataWidth
> IFX_SSC_MAX_DATA_WIDTH
)) {
1245 printk("%s: sanity check failed\n", __FUNCTION__
);
1248 bits
= (opts
->dataWidth
- 1) << IFX_SSC_CON_DATA_WIDTH_OFFSET
;
1249 bits
|= IFX_SSC_CON_ENABLE_BYTE_VALID
;
1250 // if (opts->abortErrDetect)
1251 // bits |= IFX_SSC_CON_ABORT_ERR_CHECK;
1252 if (opts
->rxOvErrDetect
)
1253 bits
|= IFX_SSC_CON_RX_OFL_CHECK
;
1254 if (opts
->rxUndErrDetect
)
1255 bits
|= IFX_SSC_CON_RX_UFL_CHECK
;
1256 if (opts
->txOvErrDetect
)
1257 bits
|= IFX_SSC_CON_TX_OFL_CHECK
;
1258 if (opts
->txUndErrDetect
)
1259 bits
|= IFX_SSC_CON_TX_UFL_CHECK
;
1261 bits
|= IFX_SSC_CON_LOOPBACK_MODE
;
1263 bits
|= IFX_SSC_CON_ECHO_MODE_ON
;
1264 if (opts
->headingControl
)
1265 bits
|= IFX_SSC_CON_MSB_FIRST
;
1266 if (opts
->clockPhase
)
1267 bits
|= IFX_SSC_CON_LATCH_THEN_SHIFT
;
1268 if (opts
->clockPolarity
)
1269 bits
|= IFX_SSC_CON_CLOCK_FALL
;
1270 switch (opts
->modeRxTx
) {
1271 case IFX_SSC_MODE_TX
:
1272 bits
|= IFX_SSC_CON_RX_OFF
;
1274 case IFX_SSC_MODE_RX
:
1275 bits
|= IFX_SSC_CON_TX_OFF
;
1277 } // switch (opts->modeRxT)
1278 local_irq_save(flags
);
1279 WRITE_PERIPHERAL_REGISTER(bits
, info
->mapbase
+ IFX_SSC_CON
);
1280 WRITE_PERIPHERAL_REGISTER((info
->opts
.gpoCs
<< IFX_SSC_GPOCON_ISCSB0_POS
) |
1281 (info
->opts
.gpoInv
<< IFX_SSC_GPOCON_INVOUT0_POS
),
1282 info
->mapbase
+ IFX_SSC_GPOCON
);
1284 if (opts
->masterSelect
){
1285 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_MASTER_SELECT
,info
->mapbase
+ IFX_SSC_WHBSTATE
);
1287 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_MASTER_SELECT
,info
->mapbase
+ IFX_SSC_WHBSTATE
);
1289 // init serial framing
1290 WRITE_PERIPHERAL_REGISTER(0, info
->mapbase
+ IFX_SSC_SFCON
);
1291 /* set up the port pins */
1292 //check for general requirements to switch (external) pad/pin characteristics
1294 local_irq_restore(flags
);
1297 } // ifx_ssc_sethwopts
1300 ifx_ssc_set_baud(struct ifx_ssc_port
*info
, unsigned int baud
)
1302 unsigned int ifx_ssc_clock
;
1304 unsigned long flags
;
1307 ifx_ssc_clock
= ifx_ssc_get_kernel_clk(info
);
1308 if (ifx_ssc_clock
==0)
1311 local_irq_save(flags
);
1312 /* have to disable the SSC to set the baudrate */
1313 enabled
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
)
1314 & IFX_SSC_STATE_IS_ENABLED
) != 0;
1315 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE
,
1316 info
->mapbase
+ IFX_SSC_WHBSTATE
);
1319 br
= ((ifx_ssc_clock
>> 1)/baud
) - 1;
1323 ((READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
) &
1324 IFX_SSC_STATE_IS_MASTER
) == 0))){
1325 local_irq_restore(flags
);
1326 printk("%s: illegal baudrate %u\n", __FUNCTION__
, baud
);
1329 WRITE_PERIPHERAL_REGISTER(br
, info
->mapbase
+ IFX_SSC_BR
);
1331 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE
,
1332 info
->mapbase
+ IFX_SSC_WHBSTATE
);
1334 local_irq_restore(flags
);
1336 } // ifx_ssc_set_baud
1339 ifx_ssc_hwinit(struct ifx_ssc_port
*info
)
1341 unsigned long flags
;
1344 /* have to disable the SSC */
1345 enabled
= (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
)
1346 & IFX_SSC_STATE_IS_ENABLED
) != 0;
1347 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE
,
1348 info
->mapbase
+ IFX_SSC_WHBSTATE
);
1350 if (ifx_ssc_sethwopts(info
) < 0)
1352 printk("%s: setting the hardware options failed\n",
1357 if (ifx_ssc_set_baud(info
, info
->baud
) < 0) {
1358 printk("%s: setting the baud rate failed\n", __FUNCTION__
);
1361 local_irq_save(flags
);
1363 WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_TXFIFO_FL
<<
1364 IFX_SSC_XFCON_ITL_OFFSET
) |
1365 IFX_SSC_XFCON_FIFO_ENABLE
,
1366 info
->mapbase
+ IFX_SSC_TXFCON
);
1368 WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_RXFIFO_FL
<<
1369 IFX_SSC_XFCON_ITL_OFFSET
) |
1370 IFX_SSC_XFCON_FIFO_ENABLE
,
1371 info
->mapbase
+ IFX_SSC_RXFCON
);
1372 local_irq_restore(flags
);
1374 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE
,
1375 info
->mapbase
+ IFX_SSC_WHBSTATE
);
1379 /*-----------------------------------------------------------------------------
1380 FUNC-NAME : ifx_ssc_batch_exec
1384 PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
1386 RESULT : Returns error code
1389 -----------------------------------------------------------------------------*/
1391 ifx_ssc_batch_exec(struct ifx_ssc_port
*info
, struct ifx_ssc_batch_list
*batch_anchor
)
1393 // ### TO DO: implement user space batch execution
1394 // first, copy the whole linked list from user to kernel space
1395 // save some hardware options
1397 // restore hardware options if selected
1399 } // ifx_ssc_batch_exec
1403 * This routine allows the driver to implement device-
1404 * specific ioctl's. If the ioctl number passed in cmd is
1405 * not recognized by the driver, it should return ENOIOCTLCMD.
1408 ifx_ssc_ioctl(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
1411 struct ifx_ssc_port
*info
;
1412 int line
, ret_val
= 0;
1413 unsigned long flags
;
1415 int from_kernel
= 0;
1417 if ((inode
== (struct inode
*)0) || (inode
== (struct inode
*)1))
1423 line
= MINOR(filp
->f_dentry
->d_inode
->i_rdev
);
1425 /* don't use more minor devices than we can support */
1426 if (line
< 0 || line
>= PORT_CNT
)
1432 case IFX_SSC_STATS_READ
:
1433 /* data must be a pointer to a struct ifx_ssc_statistics */
1435 memcpy((void *)data
, (void *)&info
->stats
,
1436 sizeof(struct ifx_ssc_statistics
));
1438 if (copy_to_user((void *)data
,
1439 (void *)&info
->stats
,
1440 sizeof(struct ifx_ssc_statistics
)))
1443 case IFX_SSC_STATS_RESET
:
1444 /* just resets the statistics counters */
1445 memset((void *)&info
->stats
, 0, sizeof(struct ifx_ssc_statistics
));
1447 case IFX_SSC_BAUD_SET
:
1448 /* if the buffers are not empty then the port is */
1449 /* busy and we shouldn't change things on-the-fly! */
1450 if (!info
->txbuf
|| !info
->rxbuf
||
1451 (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
)
1452 & IFX_SSC_STATE_BUSY
)) {
1458 flags
= *((unsigned long *)data
);
1460 if (copy_from_user((void *)&flags
,
1461 (void *)data
, sizeof(flags
)))
1471 if (ifx_ssc_set_baud(info
, flags
) < 0)
1478 case IFX_SSC_BAUD_GET
:
1480 *((unsigned int *)data
) = info
->baud
;
1482 if (copy_to_user((void *)data
,
1483 (void *)&info
->baud
,
1484 sizeof(unsigned long)))
1487 case IFX_SSC_RXTX_MODE_SET
:
1489 tmp
= *((unsigned long *)data
);
1491 if (copy_from_user((void *)&tmp
,
1492 (void *)data
, sizeof(tmp
))) {
1496 ret_val
= ifx_ssc_rxtx_mode_set(info
, tmp
);
1498 case IFX_SSC_RXTX_MODE_GET
:
1499 tmp
= READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_CON
) &
1500 (~(IFX_SSC_CON_RX_OFF
| IFX_SSC_CON_TX_OFF
));
1502 *((unsigned int *)data
) = tmp
;
1504 if (copy_to_user((void *)data
,
1511 ifx_ssc_abort(info
);
1514 case IFX_SSC_GPO_OUT_SET
:
1516 tmp
= *((unsigned long *)data
);
1518 if (copy_from_user((void *)&tmp
,
1519 (void *)data
, sizeof(tmp
))) {
1523 if (tmp
> IFX_SSC_MAX_GPO_OUT
)
1526 WRITE_PERIPHERAL_REGISTER
1527 (1<<(tmp
+ IFX_SSC_WHBGPOSTAT_SETOUT0_POS
),
1528 info
->mapbase
+ IFX_SSC_WHBGPOSTAT
);
1530 case IFX_SSC_GPO_OUT_CLR
:
1532 tmp
= *((unsigned long *)data
);
1534 if (copy_from_user((void *)&tmp
,
1535 (void *)data
, sizeof(tmp
))) {
1539 if (tmp
> IFX_SSC_MAX_GPO_OUT
)
1542 WRITE_PERIPHERAL_REGISTER
1543 (1<<(tmp
+ IFX_SSC_WHBGPOSTAT_CLROUT0_POS
),
1544 info
->mapbase
+ IFX_SSC_WHBGPOSTAT
);
1547 case IFX_SSC_GPO_OUT_GET
:
1548 tmp
= READ_PERIPHERAL_REGISTER
1549 (info
->mapbase
+ IFX_SSC_GPOSTAT
);
1551 *((unsigned int *)data
) = tmp
;
1553 if (copy_to_user((void *)data
,
1558 case IFX_SSC_FRM_STATUS_GET
:
1559 ifx_ssc_frm_status_get(info
);
1561 memcpy((void *)data
, (void *)&info
->frm_status
,
1562 sizeof(struct ifx_ssc_frm_status
));
1564 if (copy_to_user((void *)data
,
1565 (void *)&info
->frm_status
,
1566 sizeof(struct ifx_ssc_frm_status
)))
1569 case IFX_SSC_FRM_CONTROL_GET
:
1570 ifx_ssc_frm_control_get(info
);
1572 memcpy((void *)data
, (void *)&info
->frm_opts
,
1573 sizeof(struct ifx_ssc_frm_opts
));
1575 if (copy_to_user((void *)data
,
1576 (void *)&info
->frm_opts
,
1577 sizeof(struct ifx_ssc_frm_opts
)))
1580 case IFX_SSC_FRM_CONTROL_SET
:
1582 memcpy((void *)&info
->frm_opts
, (void *)data
,
1583 sizeof(struct ifx_ssc_frm_opts
));
1585 if (copy_to_user((void *)&info
->frm_opts
,
1587 sizeof(struct ifx_ssc_frm_opts
))){
1591 ret_val
= ifx_ssc_frm_control_set(info
);
1593 case IFX_SSC_HWOPTS_SET
:
1594 /* data must be a pointer to a struct ifx_ssc_hwopts */
1595 /* if the buffers are not empty then the port is */
1596 /* busy and we shouldn't change things on-the-fly! */
1597 if (!info
->txbuf
|| !info
->rxbuf
||
1598 (READ_PERIPHERAL_REGISTER(info
->mapbase
+ IFX_SSC_STATE
)
1599 & IFX_SSC_STATE_BUSY
)) {
1604 memcpy((void *)&info
->opts
, (void *)data
,
1605 sizeof(struct ifx_ssc_hwopts
));
1607 if (copy_from_user((void *)&info
->opts
,
1609 sizeof(struct ifx_ssc_hwopts
)))
1614 if (ifx_ssc_hwinit(info
) < 0)
1619 case IFX_SSC_HWOPTS_GET
:
1620 /* data must be a pointer to a struct ifx_ssc_hwopts */
1622 memcpy((void *)data
, (void *)&info
->opts
,
1623 sizeof(struct ifx_ssc_hwopts
));
1625 if (copy_to_user((void *)data
,
1626 (void *)&info
->opts
,
1627 sizeof(struct ifx_ssc_hwopts
)))
1631 ret_val
= -ENOIOCTLCMD
;
1635 } /* ifx_ssc_ioctl */
1636 EXPORT_SYMBOL(ifx_ssc_ioctl
);
1638 ///* the poll routine */
1639 //static unsigned int
1640 //ifx_ssc_poll(struct file *filp, struct poll_table_struct *pts)
1642 // int unit = MINOR(filp->f_dentry->d_inode->i_rdev);
1643 // struct ifx_ssc_port *info;
1644 // unsigned int mask = 0;
1647 // info = &isp[unit];
1649 // /* add event to the wait queues */
1650 // /* DO NOT FORGET TO DO A WAKEUP ON THESE !!!! */
1651 // poll_wait(filp, &info->pwait, pts);
1653 // /* are there bytes in the RX SW-FIFO? */
1654 // if (info->rxrp != info->rxwp)
1655 // mask |= POLLIN | POLLRDNORM;
1657 // /* free space in the TX SW-FIFO */
1658 // spc = info->txrp - info->txwp - 1;
1660 // spc += TX_BUFSIZE;
1661 //#ifdef IFX_SSC_USEDMA
1662 // /* writing always works, except in the DMA case when all descriptors */
1663 // /* are used up */
1664 // if (unit == 1 && info->dma_freecnt == 0)
1668 // mask |= POLLOUT | POLLWRNORM;
1674 ifx_ssc1_read_proc(char *page
, char **start
, off_t offset
, int count
, int *eof
, void *data
)
1677 unsigned long flags
;
1679 /* don't want any interrupts here */
1684 /* print statistics */
1685 off
+= sprintf(page
+off
, "Statistics for Infineon Synchronous Serial Controller SSC1\n");
1686 off
+= sprintf(page
+off
, "RX overflow errors %d\n", isp
[0].stats
.rxOvErr
);
1687 off
+= sprintf(page
+off
, "RX underflow errors %d\n", isp
[0].stats
.rxUnErr
);
1688 off
+= sprintf(page
+off
, "TX overflow errors %d\n", isp
[0].stats
.txOvErr
);
1689 off
+= sprintf(page
+off
, "TX underflow errors %d\n", isp
[0].stats
.txUnErr
);
1690 off
+= sprintf(page
+off
, "Abort errors %d\n", isp
[0].stats
.abortErr
);
1691 off
+= sprintf(page
+off
, "Mode errors %d\n", isp
[0].stats
.modeErr
);
1692 off
+= sprintf(page
+off
, "RX Bytes %d\n", isp
[0].stats
.rxBytes
);
1693 off
+= sprintf(page
+off
, "TX Bytes %d\n", isp
[0].stats
.txBytes
);
1695 restore_flags (flags
); /* XXXXX */
1702 * This routine prints out the appropriate serial driver version number
1708 printk("Infineon Technologies Synchronous Serial Controller (SSC) driver\n"
1709 " version %s - built %s %s\n", IFX_SSC_DRV_VERSION
, __DATE__
, __TIME__
);
1711 } /* show_version */
1715 * Due to the fact that a port can be dynamically switched between slave
1716 * and master mode using an IOCTL the hardware is not initialized here,
1717 * but in ifx_ssc_hwinit() as a result of an IOCTL.
1722 struct ifx_ssc_port
*info
;
1724 unsigned long flags
;
1727 // ### TO DO: dynamic port count evaluation due to pin multiplexing
1730 nbytes
= PORT_CNT
* sizeof(struct ifx_ssc_port
);
1731 isp
= (struct ifx_ssc_port
*)kmalloc(nbytes
, GFP_KERNEL
);
1734 printk("%s: no memory for isp\n", __FUNCTION__
);
1737 memset(isp
, 0, nbytes
);
1741 /* register the device */
1746 if ((i
= register_chrdev(maj
, "ssc", &ifx_ssc_fops
)) < 0)
1748 printk("Unable to register major %d for the Infineon SSC\n", maj
);
1754 if ((i
= register_chrdev(maj
, "ssc", &ifx_ssc_fops
)) < 0)
1756 printk("Unable to register major %d for the Infineon SSC\n", maj
);
1761 if (maj
== 0) maj
= i
;
1762 //printk("registered major %d for Infineon SSC\n", maj);
1764 /* set default values in ifx_ssc_port */
1765 for (i
= 0; i
< PORT_CNT
; i
++) {
1768 /* default values for the HwOpts */
1769 info
->opts
.AbortErrDetect
= IFX_SSC_DEF_ABRT_ERR_DETECT
;
1770 info
->opts
.rxOvErrDetect
= IFX_SSC_DEF_RO_ERR_DETECT
;
1771 info
->opts
.rxUndErrDetect
= IFX_SSC_DEF_RU_ERR_DETECT
;
1772 info
->opts
.txOvErrDetect
= IFX_SSC_DEF_TO_ERR_DETECT
;
1773 info
->opts
.txUndErrDetect
= IFX_SSC_DEF_TU_ERR_DETECT
;
1774 info
->opts
.loopBack
= IFX_SSC_DEF_LOOP_BACK
;
1775 info
->opts
.echoMode
= IFX_SSC_DEF_ECHO_MODE
;
1776 info
->opts
.idleValue
= IFX_SSC_DEF_IDLE_DATA
;
1777 info
->opts
.clockPolarity
= IFX_SSC_DEF_CLOCK_POLARITY
;
1778 info
->opts
.clockPhase
= IFX_SSC_DEF_CLOCK_PHASE
;
1779 info
->opts
.headingControl
= IFX_SSC_DEF_HEADING_CONTROL
;
1780 info
->opts
.dataWidth
= IFX_SSC_DEF_DATA_WIDTH
;
1781 info
->opts
.modeRxTx
= IFX_SSC_DEF_MODE_RXTX
;
1782 info
->opts
.gpoCs
= IFX_SSC_DEF_GPO_CS
;
1783 info
->opts
.gpoInv
= IFX_SSC_DEF_GPO_INV
;
1784 info
->opts
.masterSelect
= IFX_SSC_DEF_MASTERSLAVE
;
1785 info
->baud
= IFX_SSC_DEF_BAUDRATE
;
1788 /* values specific to SSC1 */
1790 info
->mapbase
= AMAZON_SSC_BASE_ADD_0
;
1791 // ### TO DO: power management
1793 // setting interrupt vectors
1794 info
->txirq
= IFX_SSC_TIR
;
1795 info
->rxirq
= IFX_SSC_RIR
;
1796 info
->errirq
= IFX_SSC_EIR
;
1798 info->frmirq = IFX_SSC_FIR;
1803 WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_RMC
<< IFX_CLC_RUN_DIVIDER_OFFSET
, info
->mapbase
+ IFX_SSC_CLC
);
1805 // ### TO DO: multiple instances
1807 init_waitqueue_head(&info
->rwait
);
1808 //init_waitqueue_head(&info->pwait);
1810 local_irq_save(flags
);
1812 // init serial framing register
1813 WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_SFCON
, info
->mapbase
+ IFX_SSC_SFCON
);
1815 /* try to get the interrupts */
1816 // ### TO DO: interrupt handling with multiple instances
1817 ret_val
= ifx_int_wrapper
.request(info
->txirq
, ifx_ssc_tx_int
,
1818 0, "ifx_ssc_tx", info
);
1820 printk("%s: unable to get irq %d\n", __FUNCTION__
,
1822 local_irq_restore(flags
);
1825 ret_val
= ifx_int_wrapper
.request(info
->rxirq
, ifx_ssc_rx_int
,
1826 0, "ifx_ssc_rx", info
);
1828 printk("%s: unable to get irq %d\n", __FUNCTION__
,
1830 local_irq_restore(flags
);
1833 ret_val
= ifx_int_wrapper
.request(info
->errirq
, ifx_ssc_err_int
,
1834 0, "ifx_ssc_err", info
);
1836 printk("%s: unable to get irq %d\n", __FUNCTION__
,
1838 local_irq_restore(flags
);
1842 ret_val = ifx_int_wrapper.request(info->frmirq, ifx_ssc_frm_int,
1843 0, "ifx_ssc_frm", info);
1845 printk("%s: unable to get irq %d\n", __FUNCTION__,
1847 local_irq_restore(flags);
1852 WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_IRNEN
, info
->mapbase
+ IFX_SSC_IRN_EN
);
1854 local_irq_restore(flags
);
1855 } // for (i = 0; i < PORT_CNT; i++)
1857 /* init the SSCs with default values */
1858 for (i
= 0; i
< PORT_CNT
; i
++)
1861 if (ifx_ssc_hwinit(info
) < 0)
1863 printk("%s: hardware init failed for port %d\n",
1869 /* register /proc read handler */
1870 // ### TO DO: multiple instances
1871 /* for SSC1, which is always present */
1872 create_proc_read_entry("driver/ssc1", 0, NULL
, ifx_ssc1_read_proc
, NULL
);
1876 // ### TO DO: multiple instances
1877 ifx_int_wrapper
.free(isp
[0].txirq
,&isp
[0]);
1878 ifx_int_wrapper
.free(isp
[0].rxirq
,&isp
[0]);
1879 ifx_int_wrapper
.free(isp
[0].errirq
,&isp
[0]);
1881 ifx_int_wrapper.free(isp[0].frmirq, &isp[0]);
1884 /* free up any allocated memory in the error case */
1887 } /* ifx_ssc_init */
1891 ifx_ssc_cleanup_module(void)
1895 /* free up any allocated memory */
1896 for (i
= 0; i
< PORT_CNT
; i
++)
1898 /* disable the SSC */
1899 WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE
,isp
[i
].mapbase
+ IFX_SSC_WHBSTATE
);
1900 /* free the interrupts */
1901 ifx_int_wrapper
.free(isp
[i
].txirq
, &isp
[i
]);
1902 ifx_int_wrapper
.free(isp
[i
].rxirq
, &isp
[i
]);
1903 ifx_int_wrapper
.free(isp
[i
].errirq
, &isp
[i
]);
1905 ifx_int_wrapper.free(isp[i].frmirq, &isp[i]);
1907 if (isp[i].rxbuf != NULL)
1908 kfree(isp[i].rxbuf);
1909 if (isp[i].txbuf != NULL)
1910 kfree(isp[i].txbuf);
1914 /* unregister the device */
1915 if (unregister_chrdev(maj
, "ssc"))
1917 printk("Unable to unregister major %d for the SSC\n", maj
);
1919 /* delete /proc read handler */
1920 remove_proc_entry("driver/ssc1", NULL
);
1921 remove_proc_entry("driver/ssc2", NULL
);
1922 } /* ifx_ssc_cleanup_module */
1924 module_exit(ifx_ssc_cleanup_module
);
1926 /* Module entry-points */
1927 module_init(ifx_ssc_init
);
1931 ifx_ssc_set_maj(char *str
)
1933 maj
= simple_strtol(str
, NULL
, 0);
1936 __setup("ssc_maj=", ifx_ssc_set_maj
);
1937 #endif /* !MODULE */
1939 #define AMAZON_SSC_EMSG(fmt,arg...) printk("%s: "fmt,__FUNCTION__, ##arg)
1940 /* Brief: chip select enable
1942 inline int amazon_ssc_cs_low(u32 pin
)
1945 if ((ret
=ifx_ssc_ioctl((struct inode
*)0, NULL
,IFX_SSC_GPO_OUT_CLR
, (unsigned long)&pin
))){
1946 AMAZON_SSC_EMSG("clear CS %d fails\n",pin
);
1951 EXPORT_SYMBOL(amazon_ssc_cs_low
);
1952 /* Brief: chip select disable
1954 inline int amazon_ssc_cs_high(u32 pin
)
1957 if ((ret
=ifx_ssc_ioctl((struct inode
*)0, NULL
,IFX_SSC_GPO_OUT_SET
, (unsigned long)&pin
))){
1958 AMAZON_SSC_EMSG("set CS %d fails\n", pin
);
1963 EXPORT_SYMBOL(amazon_ssc_cs_high
);
1964 /* Brief: one SSC session
1970 * session_mode: IFX_SSC_MODE_RXTX or IFX_SSC_MODE_TX
1971 * Return: >=0 number of bytes received (if rx_buf != 0) or transmitted
1974 * 0. copy data to internal buffer
1976 * 2a. If SSC_SESSION_MODE_TXONLY, read tx_len data
1977 * 2b. If not Read back (tx_len + rx_len) data
1978 * 3. copy internal buffer to rx buf if necessary
1980 static int ssc_session(char * tx_buf
, u32 tx_len
, char * rx_buf
, u32 rx_len
)
1984 char * ssc_tx_buf
=NULL
;
1985 char * ssc_rx_buf
=NULL
;
1987 // volatile char ssc_tx_buf[128]={0};
1988 // volatile char ssc_rx_buf[128]={0};
1993 if (tx_buf
== NULL
&& tx_len
==0 && rx_buf
== NULL
&& rx_len
== 0){
1994 AMAZON_SSC_EMSG("invalid parameters\n");
1996 goto ssc_session_exit
;
1997 }else if (tx_buf
== NULL
|| tx_len
== 0){
1998 if (rx_buf
!= NULL
&& rx_len
!= 0){
1999 mode
= IFX_SSC_MODE_RX
;
2001 AMAZON_SSC_EMSG("invalid parameters\n");
2003 goto ssc_session_exit
;
2005 }else if (rx_buf
== NULL
|| rx_len
==0){
2006 if (tx_buf
!= NULL
&& tx_len
!= 0){
2007 mode
= IFX_SSC_MODE_TX
;
2009 AMAZON_SSC_EMSG("invalid parameters\n");
2011 goto ssc_session_exit
;
2014 mode
= IFX_SSC_MODE_RXTX
;
2017 if (mode
== IFX_SSC_MODE_RXTX
){
2018 eff_size
= tx_len
+ rx_len
;
2019 }else if (mode
== IFX_SSC_MODE_RX
){
2025 //4 bytes alignment, required by driver
2026 /* change by TaiCheng */
2029 ssc_tx_buf
= (char*) kmalloc(sizeof(char) * ((eff_size
+ 3) & (~3)), GFP_ATOMIC
);
2030 ssc_rx_buf
= (char*) kmalloc(sizeof(char) * ((eff_size
+ 3) & (~3)), GFP_ATOMIC
);
2032 ssc_tx_buf
= (char*) kmalloc(sizeof(char) * ((eff_size
+ 3) & (~3)), GFP_KERNEL
);
2033 ssc_rx_buf
= (char*) kmalloc(sizeof(char) * ((eff_size
+ 3) & (~3)), GFP_KERNEL
);
2035 if (ssc_tx_buf
== NULL
|| ssc_rx_buf
== NULL
){
2036 AMAZON_SSC_EMSG("no memory for size of %d\n", eff_size
);
2038 goto ssc_session_exit
;
2040 memset((void*)ssc_tx_buf
, 0, eff_size
);
2041 memset((void*)ssc_rx_buf
, 0, eff_size
);
2044 memcpy(ssc_tx_buf
, tx_buf
, tx_len
);
2047 ret
=ifx_ssc_kwrite(0, ssc_tx_buf
, eff_size
);
2050 ssc_tx_buf
= NULL
; //should be freed by ifx_ssc_kwrite
2053 if ( ret
!= eff_size
){
2054 AMAZON_SSC_EMSG("ifx_ssc_write return %d\n",ret
);
2055 goto ssc_session_exit
;
2057 ret
=ifx_ssc_kread(0, ssc_rx_buf
,eff_size
);
2058 if ( ret
!= eff_size
){
2059 AMAZON_SSC_EMSG("ifx_ssc_read return %d\n",ret
);
2060 goto ssc_session_exit
;
2063 memcpy(rx_buf
, ssc_rx_buf
+tx_len
, rx_len
);
2065 if (mode
== IFX_SSC_MODE_TX
) {
2072 if (ssc_tx_buf
!= NULL
) kfree(ssc_tx_buf
);
2073 if (ssc_rx_buf
!= NULL
) kfree(ssc_rx_buf
);
2076 printk("ssc session fails\n");
2080 /* Brief: TX-RX session
2086 * Return: >=0 number of bytes received
2092 int amazon_ssc_txrx(char * tx_buf
, u32 tx_len
, char * rx_buf
, u32 rx_len
)
2094 return ssc_session(tx_buf
,tx_len
,rx_buf
,rx_len
);
2096 EXPORT_SYMBOL(amazon_ssc_txrx
);
2097 /* Brief: TX only session
2101 * Return: >=0 number of bytes transmitted
2104 int amazon_ssc_tx(char * tx_buf
, u32 tx_len
)
2106 return ssc_session(tx_buf
,tx_len
,NULL
,0);
2108 EXPORT_SYMBOL(amazon_ssc_tx
);
2109 /* Brief: RX only session
2113 * Return: >=0 number of bytes received
2116 int amazon_ssc_rx(char * rx_buf
, u32 rx_len
)
2118 return ssc_session(NULL
,0,rx_buf
,rx_len
);
2120 EXPORT_SYMBOL(amazon_ssc_rx
);