aboutsummaryrefslogtreecommitdiff
path: root/lib/lpc43xx/ssp.c
blob: e9cf5b09a2471cd13d32c39b1ec868f02378dc8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * This file is part of the libopencm3 project.
 *
 * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/cgu.h>

#define CGU_SRC_32K			0x00
#define CGU_SRC_IRC			0x01
#define CGU_SRC_ENET_RX		0x02
#define CGU_SRC_ENET_TX		0x03
#define CGU_SRC_GP_CLKIN	0x04
#define CGU_SRC_XTAL		0x06
#define CGU_SRC_PLL0USB		0x07
#define CGU_SRC_PLL0AUDIO	0x08
#define CGU_SRC_PLL1		0x09
#define CGU_SRC_IDIVA		0x0C
#define CGU_SRC_IDIVB		0x0D
#define CGU_SRC_IDIVC		0x0E
#define CGU_SRC_IDIVD		0x0F
#define CGU_SRC_IDIVE		0x10

#define CGU_AUTOBLOCK_CLOCK_BIT	11
#define CGU_BASE_CLK_SEL_SHIFT	24   /* clock source selection (5 bits) */

/* Disable SSP */
void ssp_disable(ssp_num_t ssp_num)
{
	u32 ssp_port;

	if(ssp_num == SSP0_NUM)
	{
		ssp_port = SSP0;
	}else
	{
		ssp_port = SSP1;
	}
	/* Disable SSP */
	SSP_CR1(ssp_port) = 0x0;
}

/*
* SSP Init function
*/
void ssp_init(ssp_num_t ssp_num,
			ssp_datasize_t data_size,
			ssp_frame_format_t frame_format,
			ssp_cpol_cpha_t cpol_cpha_format,
			u8 serial_clock_rate,
			u8 clk_prescale,
			ssp_mode_t mode,
			ssp_master_slave_t master_slave,
			ssp_slave_option_t slave_option)
{
	u32 ssp_port;
	u32 clock;

	if(ssp_num == SSP0_NUM)
	{
		ssp_port = SSP0;
	}else
	{
		ssp_port = SSP1;
	}

	/* use PLL1 as clock source for SSP1 */
	CGU_BASE_SSP1_CLK = (CGU_SRC_PLL1<<CGU_BASE_CLK_SEL_SHIFT) | (1<<CGU_AUTOBLOCK_CLOCK_BIT);

	/* Disable SSP before to configure it */
	SSP_CR1(ssp_port) = 0x0;

	/* Configure SSP */
	clock = serial_clock_rate;
	SSP_CPSR(ssp_port) = clk_prescale;
	SSP_CR0(ssp_port) = (data_size | frame_format | cpol_cpha_format | (clock<<8) );

	/* Enable SSP */
	SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option);
}

/*
* This Function Wait until Data RX Ready, and return Data Read from SSP.
*/
u16 ssp_read(ssp_num_t ssp_num)
{
	u32 ssp_port;

	if(ssp_num == SSP0_NUM)
	{
		ssp_port = SSP0;
	}else
	{
		ssp_port = SSP1;
	}
	/* Wait Until Data Received (Rx FIFO not Empty) */
	while( (SSP_SR(ssp_port) & SSP_SR_RNE) == 0);

	return SSP_DR(ssp_port);
}

void ssp_wait_until_not_busy(ssp_num_t ssp_num)
{
	u32 ssp_port;
	
	if(ssp_num == SSP0_NUM)
	{
		ssp_port = SSP0;
	}else
	{
		ssp_port = SSP1;
	}

	while( (SSP_SR(ssp_port) & SSP_SR_BSY) );
}

/* This Function Wait Data TX Ready, and Write Data to SSP */
void ssp_write(ssp_num_t ssp_num, u16 data)
{
	u32 ssp_port;

	if(ssp_num == SSP0_NUM)
	{
		ssp_port = SSP0;
	}else
	{
		ssp_port = SSP1;
	}

	/* Wait Until FIFO not full  */
	while( (SSP_SR(ssp_port) & SSP_SR_TNF) == 0);

	SSP_DR(ssp_port) = data;
	
	/* Wait for not busy, since we're controlling CS# of
	 * devices manually and need to wait for the data to
	 * be sent. It may also be important to wait here
	 * in case we're configuring devices via SPI and also
	 * with GPIO control -- we need to know when SPI
	 * commands are effective before altering a device's
	 * state with GPIO. I'm thinking the MAX2837, for
	 * example...
	 */
	ssp_wait_until_not_busy(ssp_num);
}