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