1 /*******************************************************************************
2  * (c) Copyright 2008-2015 Microsemi SoC Products Group.  All rights reserved.
3  *
4  * SmartFusion2 microcontroller subsystem GPIO bare metal driver implementation.
5  *
6  * SVN $Revision: 7749 $
7  * SVN $Date: 2015-09-04 14:32:09 +0530 (Fri, 04 Sep 2015) $
8  */
9 #include "mss_gpio.h"
10 #include "../../CMSIS/mss_assert.h"
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /*-------------------------------------------------------------------------*//**
17  * Defines.
18  */
19 #define GPIO_INT_ENABLE_MASK        ((uint32_t)0x00000008uL)
20 #define OUTPUT_BUFFER_ENABLE_MASK   0x00000004u
21 
22 #define NB_OF_GPIO  ((uint32_t)32)
23 
24 /*-------------------------------------------------------------------------*//**
25  * Lookup table of GPIO configuration registers address indexed on GPIO ID.
26  */
27 static uint32_t volatile * const g_config_reg_lut[NB_OF_GPIO] =
28 {
29     &(GPIO->GPIO_0_CFG),
30     &(GPIO->GPIO_1_CFG),
31     &(GPIO->GPIO_2_CFG),
32     &(GPIO->GPIO_3_CFG),
33     &(GPIO->GPIO_4_CFG),
34     &(GPIO->GPIO_5_CFG),
35     &(GPIO->GPIO_6_CFG),
36     &(GPIO->GPIO_7_CFG),
37     &(GPIO->GPIO_8_CFG),
38     &(GPIO->GPIO_9_CFG),
39     &(GPIO->GPIO_10_CFG),
40     &(GPIO->GPIO_11_CFG),
41     &(GPIO->GPIO_12_CFG),
42     &(GPIO->GPIO_13_CFG),
43     &(GPIO->GPIO_14_CFG),
44     &(GPIO->GPIO_15_CFG),
45     &(GPIO->GPIO_16_CFG),
46     &(GPIO->GPIO_17_CFG),
47     &(GPIO->GPIO_18_CFG),
48     &(GPIO->GPIO_19_CFG),
49     &(GPIO->GPIO_20_CFG),
50     &(GPIO->GPIO_21_CFG),
51     &(GPIO->GPIO_22_CFG),
52     &(GPIO->GPIO_23_CFG),
53     &(GPIO->GPIO_24_CFG),
54     &(GPIO->GPIO_25_CFG),
55     &(GPIO->GPIO_26_CFG),
56     &(GPIO->GPIO_27_CFG),
57     &(GPIO->GPIO_28_CFG),
58     &(GPIO->GPIO_29_CFG),
59     &(GPIO->GPIO_30_CFG),
60     &(GPIO->GPIO_31_CFG)
61 };
62 
63 /*-------------------------------------------------------------------------*//**
64  * Lookup table of Cortex-M3 GPIO interrupt number indexed on GPIO ID.
65  */
66 static const IRQn_Type g_gpio_irqn_lut[NB_OF_GPIO] =
67 {
68     GPIO0_IRQn,
69     GPIO1_IRQn,
70     GPIO2_IRQn,
71     GPIO3_IRQn,
72     GPIO4_IRQn,
73     GPIO5_IRQn,
74     GPIO6_IRQn,
75     GPIO7_IRQn,
76     GPIO8_IRQn,
77     GPIO9_IRQn,
78     GPIO10_IRQn,
79     GPIO11_IRQn,
80     GPIO12_IRQn,
81     GPIO13_IRQn,
82     GPIO14_IRQn,
83     GPIO15_IRQn,
84     GPIO16_IRQn,
85     GPIO17_IRQn,
86     GPIO18_IRQn,
87     GPIO19_IRQn,
88     GPIO20_IRQn,
89     GPIO21_IRQn,
90     GPIO22_IRQn,
91     GPIO23_IRQn,
92     GPIO24_IRQn,
93     GPIO25_IRQn,
94     GPIO26_IRQn,
95     GPIO27_IRQn,
96     GPIO28_IRQn,
97     GPIO29_IRQn,
98     GPIO30_IRQn,
99     GPIO31_IRQn
100 };
101 
102 /*-------------------------------------------------------------------------*//**
103  * MSS_GPIO_init
104  * See "mss_gpio.h" for details of how to use this function.
105  */
MSS_GPIO_init(void)106 void MSS_GPIO_init( void )
107 {
108     uint32_t inc;
109 
110     /* reset MSS GPIO hardware */
111     SYSREG->SOFT_RST_CR |= SYSREG_GPIO_SOFTRESET_MASK;
112     SYSREG->SOFT_RST_CR |= (SYSREG_GPIO_7_0_SOFTRESET_MASK |
113                             SYSREG_GPIO_15_8_SOFTRESET_MASK |
114                             SYSREG_GPIO_23_16_SOFTRESET_MASK |
115                             SYSREG_GPIO_31_24_SOFTRESET_MASK);
116 
117     /* Clear any previously pended MSS GPIO interrupt */
118     for(inc = 0U; inc < NB_OF_GPIO; ++inc)
119     {
120         NVIC_DisableIRQ(g_gpio_irqn_lut[inc]);
121         NVIC_ClearPendingIRQ(g_gpio_irqn_lut[inc]);
122     }
123     /* Take MSS GPIO hardware out of reset. */
124     SYSREG->SOFT_RST_CR &= ~(SYSREG_GPIO_7_0_SOFTRESET_MASK |
125                              SYSREG_GPIO_15_8_SOFTRESET_MASK |
126                              SYSREG_GPIO_23_16_SOFTRESET_MASK |
127                              SYSREG_GPIO_31_24_SOFTRESET_MASK);
128     SYSREG->SOFT_RST_CR &= ~SYSREG_GPIO_SOFTRESET_MASK;
129 }
130 
131 /*-------------------------------------------------------------------------*//**
132  * MSS_GPIO_config
133  * See "mss_gpio.h" for details of how to use this function.
134  */
MSS_GPIO_config(mss_gpio_id_t port_id,uint32_t config)135 void MSS_GPIO_config
136 (
137     mss_gpio_id_t port_id,
138     uint32_t config
139 )
140 {
141     uint32_t gpio_idx = (uint32_t)port_id;
142 
143     ASSERT(gpio_idx < NB_OF_GPIO);
144 
145     if(gpio_idx < NB_OF_GPIO)
146     {
147         *(g_config_reg_lut[gpio_idx]) = config;
148     }
149 }
150 
151 /*-------------------------------------------------------------------------*//**
152  * MSS_GPIO_set_output
153  * See "mss_gpio.h" for details of how to use this function.
154  */
MSS_GPIO_set_output(mss_gpio_id_t port_id,uint8_t value)155 void MSS_GPIO_set_output
156 (
157     mss_gpio_id_t port_id,
158     uint8_t value
159 )
160 {
161     uint32_t gpio_setting;
162     uint32_t gpio_idx = (uint32_t)port_id;
163 
164     ASSERT(gpio_idx < NB_OF_GPIO);
165 
166     if(gpio_idx < NB_OF_GPIO)
167     {
168         gpio_setting = GPIO->GPIO_OUT;
169         gpio_setting &= ~((uint32_t)0x01u << gpio_idx);
170         gpio_setting |= ((uint32_t)value & 0x01u) << gpio_idx;
171         GPIO->GPIO_OUT = gpio_setting;
172     }
173 }
174 
175 /*-------------------------------------------------------------------------*//**
176  * MSS_GPIO_drive_inout
177  * See "mss_gpio.h" for details of how to use this function.
178  */
MSS_GPIO_drive_inout(mss_gpio_id_t port_id,mss_gpio_inout_state_t inout_state)179 void MSS_GPIO_drive_inout
180 (
181     mss_gpio_id_t port_id,
182     mss_gpio_inout_state_t inout_state
183 )
184 {
185     uint32_t outputs_state;
186     uint32_t config;
187     uint32_t gpio_idx = (uint32_t)port_id;
188 
189     ASSERT(gpio_idx < NB_OF_GPIO);
190 
191     if(gpio_idx < NB_OF_GPIO)
192     {
193         switch(inout_state)
194         {
195             case MSS_GPIO_DRIVE_HIGH:
196                 /* Set output high */
197                 outputs_state = GPIO->GPIO_OUT;
198                 outputs_state |= (uint32_t)1 << gpio_idx;
199                 GPIO->GPIO_OUT = outputs_state;
200                 /* Enable output buffer */
201                 config = *(g_config_reg_lut[gpio_idx]);
202                 config |= OUTPUT_BUFFER_ENABLE_MASK;
203                 *(g_config_reg_lut[gpio_idx]) = config;
204             break;
205 
206             case MSS_GPIO_DRIVE_LOW:
207                 /* Set output low */
208                 outputs_state = GPIO->GPIO_OUT;
209                 outputs_state &= ~((uint32_t)((uint32_t)1 << gpio_idx));
210                 GPIO->GPIO_OUT = outputs_state;
211                 /* Enable output buffer */
212                 config = *(g_config_reg_lut[gpio_idx]);
213                 config |= OUTPUT_BUFFER_ENABLE_MASK;
214                 *(g_config_reg_lut[gpio_idx]) = config;
215             break;
216 
217             case MSS_GPIO_HIGH_Z:
218                 /* Disable output buffer */
219                 config = *(g_config_reg_lut[gpio_idx]);
220                 config &= ~OUTPUT_BUFFER_ENABLE_MASK;
221                 *(g_config_reg_lut[gpio_idx]) = config;
222             break;
223 
224             default:
225                 ASSERT(0);
226             break;
227         }
228     }
229 }
230 
231 /*-------------------------------------------------------------------------*//**
232  * MSS_GPIO_enable_irq
233  * See "mss_gpio.h" for details of how to use this function.
234  */
MSS_GPIO_enable_irq(mss_gpio_id_t port_id)235 void MSS_GPIO_enable_irq
236 (
237     mss_gpio_id_t port_id
238 )
239 {
240     uint32_t cfg_value;
241     uint32_t gpio_idx = (uint32_t)port_id;
242 
243     ASSERT(gpio_idx < NB_OF_GPIO);
244 
245     if(gpio_idx < NB_OF_GPIO)
246     {
247         cfg_value = *(g_config_reg_lut[gpio_idx]);
248         *(g_config_reg_lut[gpio_idx]) = (cfg_value | GPIO_INT_ENABLE_MASK);
249         NVIC_EnableIRQ(g_gpio_irqn_lut[gpio_idx]);
250     }
251 }
252 
253 /*-------------------------------------------------------------------------*//**
254  * MSS_GPIO_disable_irq
255  * See "mss_gpio.h" for details of how to use this function.
256  */
MSS_GPIO_disable_irq(mss_gpio_id_t port_id)257 void MSS_GPIO_disable_irq
258 (
259     mss_gpio_id_t port_id
260 )
261 {
262     uint32_t cfg_value;
263     uint32_t gpio_idx = (uint32_t)port_id;
264 
265     ASSERT(gpio_idx < NB_OF_GPIO);
266 
267     if(gpio_idx < NB_OF_GPIO)
268     {
269         cfg_value = *(g_config_reg_lut[gpio_idx]);
270         *(g_config_reg_lut[gpio_idx]) = (cfg_value & ~GPIO_INT_ENABLE_MASK);
271     }
272 }
273 
274 /*-------------------------------------------------------------------------*//**
275  * MSS_GPIO_clear_irq
276  * See "mss_gpio.h" for details of how to use this function.
277  */
MSS_GPIO_clear_irq(mss_gpio_id_t port_id)278 void MSS_GPIO_clear_irq
279 (
280     mss_gpio_id_t port_id
281 )
282 {
283     uint32_t gpio_idx = (uint32_t)port_id;
284 
285     ASSERT(gpio_idx < NB_OF_GPIO);
286 
287     if(gpio_idx < NB_OF_GPIO)
288     {
289         GPIO->GPIO_IRQ = ((uint32_t)1) << gpio_idx;
290     }
291     __ASM volatile ("dsb");
292 
293 }
294 
295 #ifdef __cplusplus
296 }
297 #endif
298 
299