1 /**
2  *
3  * \file
4  *
5  * \brief KS8851SNL driver for SAM.
6  *
7  * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
8  *
9  * \asf_license_start
10  *
11  * \page License
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  *    this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright notice,
20  *    this list of conditions and the following disclaimer in the documentation
21  *    and/or other materials provided with the distribution.
22  *
23  * 3. The name of Atmel may not be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * 4. This software may only be redistributed and used in connection with an
27  *    Atmel microcontroller product.
28  *
29  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
30  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
32  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
33  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  *
41  * \asf_license_stop
42  *
43  */
44 
45 /*
46  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
47  */
48 
49 /* FreeRTOS includes. */
50 #include "FreeRTOS.h"
51 #include "task.h"
52 
53 #include "spi_master.h"
54 #include "ksz8851snl.h"
55 #include "ksz8851snl_reg.h"
56 #include "delay.h"
57 #include "pio.h"
58 #include "pio_handler.h"
59 #include "pdc.h"
60 #include "conf_eth.h"
61 
62 /* Clock polarity. */
63 #define SPI_CLK_POLARITY    0
64 
65 /* Clock phase. */
66 #define SPI_CLK_PHASE       1
67 
68 /* SPI PDC register base. */
69 Pdc * g_p_spi_pdc = 0;
70 
71 int lUDPLoggingPrintf( const char * pcFormatString,
72                        ... );
73 
74 /* Temporary buffer for PDC reception. */
75 uint8_t tmpbuf[ 1536 ] __attribute__( ( aligned( 16 ) ) );
76 
77 union
78 {
79     uint64_t ul[ 2 ];
80     uint8_t uc[ 16 ];
81 }
82 cmdBuf, respBuf;
83 
84 void dbg_add_line( const char * pcFormat,
85                    ... );
86 
87 static void spi_clear_ovres( void );
88 
89 /**
90  * \brief Read register content, set bitmask and write back to register.
91  *
92  * \param reg the register address to modify.
93  * \param bits_to_set bitmask to apply.
94  */
ksz8851_reg_setbits(uint16_t reg,uint16_t bits_to_set)95 void ksz8851_reg_setbits( uint16_t reg,
96                           uint16_t bits_to_set )
97 {
98     uint16_t temp;
99 
100     temp = ksz8851_reg_read( reg );
101     temp |= bits_to_set;
102     ksz8851_reg_write( reg, temp );
103 }
104 
105 /**
106  * \brief Read register content, clear bitmask and write back to register.
107  *
108  * \param reg the register address to modify.
109  * \param bits_to_set bitmask to apply.
110  */
ksz8851_reg_clrbits(uint16_t reg,uint16_t bits_to_clr)111 void ksz8851_reg_clrbits( uint16_t reg,
112                           uint16_t bits_to_clr )
113 {
114     uint16_t temp;
115 
116     temp = ksz8851_reg_read( reg );
117     temp &= ~( uint32_t ) bits_to_clr;
118     ksz8851_reg_write( reg, temp );
119 }
120 
121 /**
122  * \brief Configure the INTN interrupt.
123  */
configure_intn(void (* p_handler)(uint32_t,uint32_t))124 void configure_intn( void ( * p_handler )( uint32_t, uint32_t ) )
125 {
126 /*	gpio_configure_pin(KSZ8851SNL_INTN_GPIO, PIO_INPUT); */
127 /*	pio_set_input(PIOA, PIO_PA11_IDX, PIO_PULLUP); */
128 
129     /* Configure PIO clock. */
130     pmc_enable_periph_clk( INTN_ID );
131 
132     /* Adjust PIO debounce filter parameters, uses 10 Hz filter. */
133     pio_set_debounce_filter( INTN_PIO, INTN_PIN_MSK, 10 );
134 
135     /* Initialize PIO interrupt handlers, see PIO definition in board.h. */
136     pio_handler_set( INTN_PIO, INTN_ID, INTN_PIN_MSK,
137                      INTN_ATTR, p_handler );
138 
139     /* Enable NVIC interrupts. */
140     NVIC_SetPriority( INTN_IRQn, INT_PRIORITY_PIO );
141     NVIC_EnableIRQ( ( IRQn_Type ) INTN_ID );
142 
143     /* Enable PIO interrupts. */
144     pio_enable_interrupt( INTN_PIO, INTN_PIN_MSK );
145 }
146 
147 /**
148  * \brief Read a register value.
149  *
150  * \param reg the register address to modify.
151  *
152  * \return the register value.
153  */
ksz8851_reg_read(uint16_t reg)154 uint16_t ksz8851_reg_read( uint16_t reg )
155 {
156     pdc_packet_t g_pdc_spi_tx_packet;
157     pdc_packet_t g_pdc_spi_rx_packet;
158     uint16_t cmd = 0;
159     uint16_t res = 0;
160     int iTryCount = 3;
161 
162     while( iTryCount-- > 0 )
163     {
164         uint32_t ulStatus;
165 
166         spi_clear_ovres();
167         /* Move register address to cmd bits 9-2, make 32-bit address. */
168         cmd = ( reg << 2 ) & REG_ADDR_MASK;
169 
170         /* Last 2 bits still under "don't care bits" handled with byte enable. */
171         /* Select byte enable for command. */
172         if( reg & 2 )
173         {
174             /* Odd word address writes bytes 2 and 3 */
175             cmd |= ( 0xc << 10 );
176         }
177         else
178         {
179             /* Even word address write bytes 0 and 1 */
180             cmd |= ( 0x3 << 10 );
181         }
182 
183         /* Add command read code. */
184         cmd |= CMD_READ;
185         cmdBuf.uc[ 0 ] = cmd >> 8;
186         cmdBuf.uc[ 1 ] = cmd & 0xff;
187         cmdBuf.uc[ 2 ] = CONFIG_SPI_MASTER_DUMMY;
188         cmdBuf.uc[ 3 ] = CONFIG_SPI_MASTER_DUMMY;
189 
190         /* Prepare PDC transfer. */
191         g_pdc_spi_tx_packet.ul_addr = ( uint32_t ) cmdBuf.uc;
192         g_pdc_spi_tx_packet.ul_size = 4;
193         g_pdc_spi_rx_packet.ul_addr = ( uint32_t ) tmpbuf;
194         g_pdc_spi_rx_packet.ul_size = 4;
195         pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
196         pdc_tx_init( g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL );
197         pdc_rx_init( g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL );
198         gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
199 
200         spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );
201         pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
202 
203         for( ; ; )
204         {
205             ulStatus = spi_read_status( KSZ8851SNL_SPI );
206 
207             if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )
208             {
209                 break;
210             }
211         }
212 
213         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
214 
215         if( ( ulStatus & SPI_SR_OVRES ) == 0 )
216         {
217             break;
218         }
219 
220         pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
221         lUDPLoggingPrintf( "ksz8851_reg_read: SPI_SR_OVRES\n" );
222     }
223 
224     res = ( tmpbuf[ 3 ] << 8 ) | tmpbuf[ 2 ];
225     return res;
226 }
227 
228 /**
229  * \brief Write a register value.
230  *
231  * \param reg the register address to modify.
232  * \param wrdata the new register value.
233  */
ksz8851_reg_write(uint16_t reg,uint16_t wrdata)234 void ksz8851_reg_write( uint16_t reg,
235                         uint16_t wrdata )
236 {
237     pdc_packet_t g_pdc_spi_tx_packet;
238     pdc_packet_t g_pdc_spi_rx_packet;
239     uint16_t cmd = 0;
240     int iTryCount = 3;
241 
242     while( iTryCount-- > 0 )
243     {
244         uint32_t ulStatus;
245 
246 
247         spi_clear_ovres();
248         /* Move register address to cmd bits 9-2, make 32-bit address. */
249         cmd = ( reg << 2 ) & REG_ADDR_MASK;
250 
251         /* Last 2 bits still under "don't care bits" handled with byte enable. */
252         /* Select byte enable for command. */
253         if( reg & 2 )
254         {
255             /* Odd word address writes bytes 2 and 3 */
256             cmd |= ( 0xc << 10 );
257         }
258         else
259         {
260             /* Even word address write bytes 0 and 1 */
261             cmd |= ( 0x3 << 10 );
262         }
263 
264         /* Add command write code. */
265         cmd |= CMD_WRITE;
266         cmdBuf.uc[ 0 ] = cmd >> 8;
267         cmdBuf.uc[ 1 ] = cmd & 0xff;
268         cmdBuf.uc[ 2 ] = wrdata & 0xff;
269         cmdBuf.uc[ 3 ] = wrdata >> 8;
270 
271         /* Prepare PDC transfer. */
272         g_pdc_spi_tx_packet.ul_addr = ( uint32_t ) cmdBuf.uc;
273         g_pdc_spi_tx_packet.ul_size = 4;
274         g_pdc_spi_rx_packet.ul_addr = ( uint32_t ) tmpbuf;
275         g_pdc_spi_rx_packet.ul_size = 4;
276         pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
277         pdc_tx_init( g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL );
278         pdc_rx_init( g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL );
279         gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
280 
281         spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );
282 
283         pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
284 
285         for( ; ; )
286         {
287             ulStatus = spi_read_status( KSZ8851SNL_SPI );
288 
289             if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )
290             {
291                 break;
292             }
293         }
294 
295         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
296 
297         if( ( ulStatus & SPI_SR_OVRES ) == 0 )
298         {
299             break;
300         }
301 
302         pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
303         lUDPLoggingPrintf( "ksz8851_reg_write: SPI_SR_OVRES\n" );
304     }
305 }
306 
spi_clear_ovres(void)307 static void spi_clear_ovres( void )
308 {
309     volatile uint32_t rc;
310 
311     rc = KSZ8851SNL_SPI->SPI_RDR;
312 
313     spi_read_status( KSZ8851SNL_SPI );
314 }
315 
316 /**
317  * \brief Read internal fifo buffer.
318  *
319  * \param buf the buffer to store the data from the fifo buffer.
320  * \param len the amount of data to read.
321  */
ksz8851_fifo_read(uint8_t * buf,uint32_t len)322 void ksz8851_fifo_read( uint8_t * buf,
323                         uint32_t len )
324 {
325     pdc_packet_t g_pdc_spi_tx_packet;
326     pdc_packet_t g_pdc_spi_rx_packet;
327     pdc_packet_t g_pdc_spi_tx_npacket;
328     pdc_packet_t g_pdc_spi_rx_npacket;
329 
330     memset( cmdBuf.uc, '\0', sizeof cmdBuf );
331     cmdBuf.uc[ 0 ] = FIFO_READ;
332     spi_clear_ovres();
333 
334     /* Prepare PDC transfer. */
335     g_pdc_spi_tx_packet.ul_addr = ( uint32_t ) cmdBuf.uc;
336     g_pdc_spi_tx_packet.ul_size = 9;
337     g_pdc_spi_rx_packet.ul_addr = ( uint32_t ) respBuf.uc;
338     g_pdc_spi_rx_packet.ul_size = 9;
339 
340     g_pdc_spi_tx_npacket.ul_addr = ( uint32_t ) buf;
341     g_pdc_spi_tx_npacket.ul_size = len;
342     g_pdc_spi_rx_npacket.ul_addr = ( uint32_t ) buf;
343     g_pdc_spi_rx_npacket.ul_size = len;
344     pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
345     pdc_tx_init( g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket );
346     pdc_rx_init( g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket );
347 
348     spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF | SPI_IER_OVRES );
349 
350     pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
351 }
352 
353 /**
354  * \brief Write internal fifo buffer.
355  *
356  * \param buf the buffer to send to the fifo buffer.
357  * \param ulActualLength the total amount of data to write.
358  * \param ulFIFOLength the size of the first pbuf to write from the pbuf chain.
359  */
ksz8851_fifo_write(uint8_t * buf,uint32_t ulActualLength,uint32_t ulFIFOLength)360 void ksz8851_fifo_write( uint8_t * buf,
361                          uint32_t ulActualLength,
362                          uint32_t ulFIFOLength )
363 {
364     static uint8_t frameID = 0;
365 
366     pdc_packet_t g_pdc_spi_tx_packet;
367     pdc_packet_t g_pdc_spi_rx_packet;
368     pdc_packet_t g_pdc_spi_tx_npacket;
369     pdc_packet_t g_pdc_spi_rx_npacket;
370 
371     /* Prepare control word and byte count. */
372     cmdBuf.uc[ 0 ] = FIFO_WRITE;
373     cmdBuf.uc[ 1 ] = frameID++ & 0x3f;
374     cmdBuf.uc[ 2 ] = 0;
375     cmdBuf.uc[ 3 ] = ulActualLength & 0xff;
376     cmdBuf.uc[ 4 ] = ulActualLength >> 8;
377 
378     spi_clear_ovres();
379 
380     /* Prepare PDC transfer. */
381     g_pdc_spi_tx_packet.ul_addr = ( uint32_t ) cmdBuf.uc;
382     g_pdc_spi_tx_packet.ul_size = 5;
383 
384     g_pdc_spi_rx_packet.ul_addr = ( uint32_t ) respBuf.uc;
385     g_pdc_spi_rx_packet.ul_size = 5;
386 
387     g_pdc_spi_tx_npacket.ul_addr = ( uint32_t ) buf;
388     g_pdc_spi_tx_npacket.ul_size = ulFIFOLength;
389 
390     g_pdc_spi_rx_npacket.ul_addr = ( uint32_t ) tmpbuf;
391     g_pdc_spi_rx_npacket.ul_size = ulFIFOLength;
392 
393     pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
394     pdc_tx_init( g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket );
395     #if ( TX_USES_RECV == 1 )
396         pdc_rx_init( g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket );
397         spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_ENDRX | SPI_IER_OVRES );
398         pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
399     #else
400         spi_enable_interrupt( KSZ8851SNL_SPI, SPI_SR_TXBUFE | SPI_IER_OVRES );
401         pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_TXTEN );
402     #endif
403 }
404 
405 /**
406  * \brief Write dummy data to the internal fifo buffer.
407  *
408  * \param len the amount of dummy data to write.
409  */
ksz8851_fifo_dummy(uint32_t len)410 void ksz8851_fifo_dummy( uint32_t len )
411 {
412     pdc_packet_t g_pdc_spi_tx_packet;
413     pdc_packet_t g_pdc_spi_rx_packet;
414 
415     /* Prepare PDC transfer. */
416     g_pdc_spi_tx_packet.ul_addr = ( uint32_t ) tmpbuf;
417     g_pdc_spi_tx_packet.ul_size = len;
418     g_pdc_spi_rx_packet.ul_addr = ( uint32_t ) tmpbuf;
419     g_pdc_spi_rx_packet.ul_size = len;
420     pdc_disable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
421     pdc_tx_init( g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL );
422     pdc_rx_init( g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL );
423     pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
424 
425     while( !( spi_read_status( KSZ8851SNL_SPI ) & SPI_SR_ENDRX ) )
426     {
427     }
428 }
429 
ksz8851snl_set_registers(void)430 void ksz8851snl_set_registers( void )
431 {
432     /* Init step2-4: write QMU MAC address (low, middle then high). */
433     ksz8851_reg_write( REG_MAC_ADDR_0, ( ETHERNET_CONF_ETHADDR4 << 8 ) | ETHERNET_CONF_ETHADDR5 );
434     ksz8851_reg_write( REG_MAC_ADDR_2, ( ETHERNET_CONF_ETHADDR2 << 8 ) | ETHERNET_CONF_ETHADDR3 );
435     ksz8851_reg_write( REG_MAC_ADDR_4, ( ETHERNET_CONF_ETHADDR0 << 8 ) | ETHERNET_CONF_ETHADDR1 );
436 
437     /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */
438     ksz8851_reg_write( REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC );
439 
440     /* Init step6: configure QMU transmit control register. */
441     ksz8851_reg_write( REG_TX_CTRL,
442                        TX_CTRL_ICMP_CHECKSUM |
443                        TX_CTRL_UDP_CHECKSUM |
444                        TX_CTRL_TCP_CHECKSUM |
445                        TX_CTRL_IP_CHECKSUM |
446                        TX_CTRL_FLOW_ENABLE |
447                        TX_CTRL_PAD_ENABLE |
448                        TX_CTRL_CRC_ENABLE
449                        );
450 
451     /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */
452     ksz8851_reg_write( REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC );
453 
454     /* Init step8: configure QMU Receive Frame Threshold for one frame. */
455     ksz8851_reg_write( REG_RX_FRAME_CNT_THRES, 1 );
456 
457     /* Init step9: configure QMU receive control register1. */
458     ksz8851_reg_write( REG_RX_CTRL1,
459                        RX_CTRL_UDP_CHECKSUM |
460                        RX_CTRL_TCP_CHECKSUM |
461                        RX_CTRL_IP_CHECKSUM |
462                        RX_CTRL_MAC_FILTER |
463                        RX_CTRL_FLOW_ENABLE |
464                        RX_CTRL_BROADCAST |
465                        RX_CTRL_ALL_MULTICAST |
466                        RX_CTRL_UNICAST );
467 /*	ksz8851_reg_write(REG_RX_CTRL1, */
468 /*			RX_CTRL_UDP_CHECKSUM | */
469 /*			RX_CTRL_TCP_CHECKSUM | */
470 /*			RX_CTRL_IP_CHECKSUM | */
471 /*			RX_CTRL_FLOW_ENABLE | */
472 /*			RX_CTRL_PROMISCUOUS); */
473 
474     ksz8851_reg_write( REG_RX_CTRL2,
475                        RX_CTRL_IPV6_UDP_NOCHECKSUM |
476                        RX_CTRL_UDP_LITE_CHECKSUM |
477                        RX_CTRL_ICMP_CHECKSUM |
478                        RX_CTRL_BURST_LEN_FRAME );
479 
480 
481 /*#define   RXQ_TWOBYTE_OFFSET          (0x0200)    / * Enable adding 2-byte before frame header for IP aligned with DWORD * / */
482     #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
483         {
484             #warning Remember to try the above option to get a 2-byte offset
485         }
486     #endif
487 
488     /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */
489     ksz8851_reg_write( REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET );
490 
491     /* Init step12: adjust SPI data output delay. */
492     ksz8851_reg_write( REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1 );
493 
494     /* Init step13: restart auto-negotiation. */
495     ksz8851_reg_setbits( REG_PORT_CTRL, PORT_AUTO_NEG_RESTART );
496 
497     /* Init step13.1: force link in half duplex if auto-negotiation failed. */
498     if( ( ksz8851_reg_read( REG_PORT_CTRL ) & PORT_AUTO_NEG_RESTART ) != PORT_AUTO_NEG_RESTART )
499     {
500         ksz8851_reg_clrbits( REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX );
501     }
502 
503     /* Init step14: clear interrupt status. */
504     ksz8851_reg_write( REG_INT_STATUS, 0xFFFF );
505 
506     /* Init step15: set interrupt mask. */
507     ksz8851_reg_write( REG_INT_MASK, INT_RX );
508 
509     /* Init step16: enable QMU Transmit. */
510     ksz8851_reg_setbits( REG_TX_CTRL, TX_CTRL_ENABLE );
511 
512     /* Init step17: enable QMU Receive. */
513     ksz8851_reg_setbits( REG_RX_CTRL1, RX_CTRL_ENABLE );
514 }
515 
516 /**
517  * \brief KSZ8851SNL initialization function.
518  *
519  * \return 0 on success, 1 on communication error.
520  */
ksz8851snl_init(void)521 uint32_t ksz8851snl_init( void )
522 {
523     uint32_t count = 10;
524     uint16_t dev_id = 0;
525     uint8_t id_ok = 0;
526 
527     /* Configure the SPI peripheral. */
528     spi_enable_clock( KSZ8851SNL_SPI );
529     spi_disable( KSZ8851SNL_SPI );
530     spi_reset( KSZ8851SNL_SPI );
531     spi_set_master_mode( KSZ8851SNL_SPI );
532     spi_disable_mode_fault_detect( KSZ8851SNL_SPI );
533     spi_set_peripheral_chip_select_value( KSZ8851SNL_SPI, ~( uint32_t ) ( 1UL << KSZ8851SNL_CS_PIN ) );
534     spi_set_fixed_peripheral_select( KSZ8851SNL_SPI );
535 /*spi_disable_peripheral_select_decode(KSZ8851SNL_SPI); */
536 
537     spi_set_clock_polarity( KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_POLARITY );
538     spi_set_clock_phase( KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_PHASE );
539     spi_set_bits_per_transfer( KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN,
540                                SPI_CSR_BITS_8_BIT );
541     spi_set_baudrate_div( KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, ( sysclk_get_cpu_hz() / KSZ8851SNL_CLOCK_SPEED ) );
542 /*	spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, CONFIG_SPI_MASTER_DELAY_BS, */
543 /*			CONFIG_SPI_MASTER_DELAY_BCT); */
544 
545 
546     spi_set_transfer_delay( KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, 0, 0 );
547 
548     spi_enable( KSZ8851SNL_SPI );
549 
550     /* Get pointer to UART PDC register base. */
551     g_p_spi_pdc = spi_get_pdc_base( KSZ8851SNL_SPI );
552     pdc_enable_transfer( g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
553 
554     /* Control RSTN and CSN pin from the driver. */
555     gpio_configure_pin( KSZ8851SNL_CSN_GPIO, KSZ8851SNL_CSN_FLAGS );
556     gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
557     gpio_configure_pin( KSZ8851SNL_RSTN_GPIO, KSZ8851SNL_RSTN_FLAGS );
558 
559     /* Reset the Micrel in a proper state. */
560     while( count-- )
561     {
562         /* Perform hardware reset with respect to the reset timing from the datasheet. */
563         gpio_set_pin_low( KSZ8851SNL_RSTN_GPIO );
564         vTaskDelay( 2 );
565         gpio_set_pin_high( KSZ8851SNL_RSTN_GPIO );
566         vTaskDelay( 2 );
567 
568         /* Init step1: read chip ID. */
569         dev_id = ksz8851_reg_read( REG_CHIP_ID );
570 
571         if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )
572         {
573             id_ok = 1;
574             break;
575         }
576     }
577 
578     if( id_ok != 0 )
579     {
580         ksz8851snl_set_registers();
581     }
582 
583     return id_ok ? 1 : -1;
584 }
585 
ksz8851snl_reinit(void)586 uint32_t ksz8851snl_reinit( void )
587 {
588     uint32_t count = 10;
589     uint16_t dev_id = 0;
590     uint8_t id_ok = 0;
591 
592     /* Reset the Micrel in a proper state. */
593     while( count-- )
594     {
595         /* Perform hardware reset with respect to the reset timing from the datasheet. */
596         gpio_set_pin_low( KSZ8851SNL_RSTN_GPIO );
597         vTaskDelay( 2 );
598         gpio_set_pin_high( KSZ8851SNL_RSTN_GPIO );
599         vTaskDelay( 2 );
600 
601         /* Init step1: read chip ID. */
602         dev_id = ksz8851_reg_read( REG_CHIP_ID );
603 
604         if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )
605         {
606             id_ok = 1;
607             break;
608         }
609     }
610 
611     if( id_ok != 0 )
612     {
613         ksz8851snl_set_registers();
614     }
615 
616     return id_ok ? 1 : -1;
617 }
618 
ksz8851snl_reset_rx(void)619 uint32_t ksz8851snl_reset_rx( void )
620 {
621     uint16_t usValue;
622 
623     usValue = ksz8851_reg_read( REG_RX_CTRL1 );
624 
625     usValue &= ~( ( uint16_t ) RX_CTRL_ENABLE | RX_CTRL_FLUSH_QUEUE );
626 
627     ksz8851_reg_write( REG_RX_CTRL1, usValue );
628     vTaskDelay( 2 );
629     ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_FLUSH_QUEUE );
630     vTaskDelay( 1 );
631     ksz8851_reg_write( REG_RX_CTRL1, usValue );
632     vTaskDelay( 1 );
633     ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_ENABLE );
634     vTaskDelay( 1 );
635 
636     return ( uint32_t ) usValue;
637 }
638 
ksz8851snl_reset_tx(void)639 uint32_t ksz8851snl_reset_tx( void )
640 {
641     uint16_t usValue;
642 
643     usValue = ksz8851_reg_read( REG_TX_CTRL );
644 
645     usValue &= ~( ( uint16_t ) TX_CTRL_ENABLE | TX_CTRL_FLUSH_QUEUE );
646 
647     ksz8851_reg_write( REG_TX_CTRL, usValue );
648     vTaskDelay( 2 );
649     ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_FLUSH_QUEUE );
650     vTaskDelay( 1 );
651     ksz8851_reg_write( REG_TX_CTRL, usValue );
652     vTaskDelay( 1 );
653     ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_ENABLE );
654     vTaskDelay( 1 );
655 
656     return ( uint32_t ) usValue;
657 }
658