1 /*!
2 * \file gpio-ioe.h
3 *
4 * \brief IO expander driver implementation (based on the sx1509)
5 *
6 * \copyright Revised BSD License, see section \ref LICENSE.
7 *
8 * \code
9 * ______ _
10 * / _____) _ | |
11 * ( (____ _____ ____ _| |_ _____ ____| |__
12 * \____ \| ___ | (_ _) ___ |/ ___) _ \
13 * _____) ) ____| | | || |_| ____( (___| | | |
14 * (______/|_____)_|_|_| \__)_____)\____)_| |_|
15 * (C)2013-2017 Semtech
16 *
17 * \endcode
18 *
19 * \author Miguel Luis ( Semtech )
20 *
21 * \author Gregory Cristian ( Semtech )
22 */
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include "gpio-ioe.h"
26 #include "sx1509.h"
27
28 static Gpio_t *GpioIrq[16];
29
GpioIoeInit(Gpio_t * obj,PinNames pin,PinModes mode,PinConfigs config,PinTypes type,uint32_t value)30 void GpioIoeInit( Gpio_t *obj, PinNames pin, PinModes mode, PinConfigs config, PinTypes type, uint32_t value )
31 {
32 uint8_t regAdd = 0;
33 uint8_t regVal = 0;
34 uint8_t tempVal = 0;
35
36 SX1509Init( );
37
38 obj->pin = pin;
39 obj->pinIndex = ( 0x01 << pin % 16 );
40
41 if( ( obj->pin % 16 ) > 0x07 )
42 {
43 regAdd = RegDirB;
44 obj->pinIndex = ( obj->pinIndex >> 8 ) & 0x00FF;
45 }
46 else
47 {
48 regAdd = RegDirA;
49 obj->pinIndex = ( obj->pinIndex ) & 0x00FF;
50 }
51
52 SX1509Read( regAdd, ®Val );
53
54 if( mode == PIN_OUTPUT )
55 {
56 regVal = regVal & ~obj->pinIndex;
57 }
58 else
59 {
60 regVal = regVal | obj->pinIndex;
61 }
62 SX1509Write( regAdd, regVal );
63
64
65 if( ( obj->pin % 16 ) > 0x07 )
66 {
67 SX1509Read( RegOpenDrainB, &tempVal );
68 if( config == PIN_OPEN_DRAIN )
69 {
70 SX1509Write( RegOpenDrainB, tempVal | obj->pinIndex );
71 }
72 else
73 {
74 SX1509Write( RegOpenDrainB, tempVal & ~obj->pinIndex );
75 }
76 regAdd = RegDataB;
77 }
78 else
79 {
80 SX1509Read( RegOpenDrainA, &tempVal );
81 if( config == PIN_OPEN_DRAIN )
82 {
83 SX1509Write( RegOpenDrainA, tempVal | obj->pinIndex );
84 }
85 else
86 {
87 SX1509Write( RegOpenDrainA, tempVal & ~obj->pinIndex );
88 }
89 regAdd = RegDataA;
90 }
91
92 SX1509Read( regAdd, ®Val );
93
94 // Sets initial output value
95 if( value == 0 )
96 {
97 regVal = regVal & ~obj->pinIndex;
98 }
99 else
100 {
101 regVal = regVal | obj->pinIndex;
102 }
103 SX1509Write( regAdd, regVal );
104 }
105
GpioIoeSetContext(Gpio_t * obj,void * context)106 void GpioIoeSetContext( Gpio_t *obj, void* context )
107 {
108 obj->Context = context;
109 }
110
GpioIoeSetInterrupt(Gpio_t * obj,IrqModes irqMode,IrqPriorities irqPriority,GpioIrqHandler * irqHandler)111 void GpioIoeSetInterrupt( Gpio_t *obj, IrqModes irqMode, IrqPriorities irqPriority, GpioIrqHandler *irqHandler )
112 {
113 uint8_t regAdd = 0;
114 uint8_t regVal = 0;
115 uint8_t i = 0;
116 uint16_t tempVal = 0;
117 uint8_t val = 0;
118
119 if( irqHandler == NULL )
120 {
121 return;
122 }
123
124 obj->IrqHandler = irqHandler;
125
126 if( ( obj->pin % 16 ) > 0x07 )
127 {
128 regAdd = RegInterruptMaskB;
129 }
130 else
131 {
132 regAdd = RegInterruptMaskA;
133 }
134
135 SX1509Read( regAdd, ®Val );
136
137 regVal = regVal & ~( obj->pinIndex );
138 SX1509Write( regAdd, regVal );
139
140 if( irqMode == IRQ_RISING_EDGE )
141 {
142 val = 0x01;
143 }
144 else if( irqMode == IRQ_FALLING_EDGE )
145 {
146 val = 0x02;
147 }
148 else // IRQ_RISING_FALLING_EDGE
149 {
150 val = 0x03;
151 }
152
153 tempVal = 0x0000;
154 i = 0;
155 while( tempVal != obj->pinIndex )
156 {
157 tempVal = 0x01 << i;
158 i++;
159 }
160
161 if( i < 4 )
162 {
163 regAdd = RegSenseLowA;
164 }
165 else if( i < 9 )
166 {
167 regAdd = RegSenseHighA;
168 }
169 else if( i < 13 )
170 {
171 regAdd = RegSenseLowB;
172 }
173 else
174 {
175 regAdd = RegSenseHighB;
176 }
177 SX1509Read( regAdd, ®Val );
178
179 switch( i )
180 {
181 case 1:
182 case 5:
183 case 9:
184 case 13:
185 regVal = ( regVal & REG_SENSE_PIN_MASK_1 ) | val;
186 break;
187
188 case 2:
189 case 6:
190 case 10:
191 case 14:
192 regVal = ( regVal & REG_SENSE_PIN_MASK_2 ) | ( val << 2 );
193 break;
194
195 case 3:
196 case 7:
197 case 11:
198 case 15:
199 regVal = ( regVal & REG_SENSE_PIN_MASK_3 ) | ( val << 4 );
200 break;
201
202 case 4:
203 case 8:
204 case 12:
205 case 16:
206 regVal = ( regVal & REG_SENSE_PIN_MASK_4 ) | ( val << 6 );
207 break;
208 }
209 SX1509Write( regAdd, regVal );
210
211 GpioIrq[obj->pin & 0x0F] = obj;
212 }
213
GpioIoeRemoveInterrupt(Gpio_t * obj)214 void GpioIoeRemoveInterrupt( Gpio_t *obj )
215 {
216 uint8_t regAdd = 0;
217 uint8_t regVal = 0;
218 uint8_t i = 0;
219 uint16_t tempVal = 0;
220
221 // Clear callback before changing pin mode
222 GpioIrq[obj->pin & 0x0F] = NULL;
223
224 if( ( obj->pin % 16 ) > 0x07 )
225 {
226 regAdd = RegInterruptMaskB;
227 }
228 else
229 {
230 regAdd = RegInterruptMaskA;
231 }
232
233 SX1509Read( regAdd, ®Val );
234
235 regVal = regVal | obj->pinIndex;
236 SX1509Write( regAdd, regVal );
237
238 tempVal = 0x0000;
239 i = 0;
240 while( tempVal != obj->pinIndex )
241 {
242 tempVal = 0x01 << i;
243 i++;
244 }
245
246 if( i < 4 )
247 {
248 regAdd = RegSenseLowA;
249 }
250 else if( i < 9 )
251 {
252 regAdd = RegSenseHighA;
253 }
254 else if( i < 13 )
255 {
256 regAdd = RegSenseLowB;
257 }
258 else
259 {
260 regAdd = RegSenseHighB;
261 }
262 SX1509Read( regAdd, ®Val );
263
264 switch( i )
265 {
266 case 1:
267 case 5:
268 case 9:
269 case 13:
270 regVal = ( regVal & REG_SENSE_PIN_MASK_1 );
271 break;
272
273 case 2:
274 case 6:
275 case 10:
276 case 14:
277 regVal = ( regVal & REG_SENSE_PIN_MASK_2 );
278 break;
279
280 case 3:
281 case 7:
282 case 11:
283 case 15:
284 regVal = ( regVal & REG_SENSE_PIN_MASK_3 );
285 break;
286
287 case 4:
288 case 8:
289 case 12:
290 case 16:
291 regVal = ( regVal & REG_SENSE_PIN_MASK_4 );
292 break;
293 }
294 SX1509Write( regAdd, regVal );
295 }
296
GpioIoeWrite(Gpio_t * obj,uint32_t value)297 void GpioIoeWrite( Gpio_t *obj, uint32_t value )
298 {
299 uint8_t regAdd = 0;
300 uint8_t regVal = 0;
301
302 if( ( obj->pin % 16 ) > 0x07 )
303 {
304 regAdd = RegDataB;
305 }
306 else
307 {
308 regAdd = RegDataA;
309 }
310
311 SX1509Read( regAdd, ®Val );
312
313 // Sets initial output value
314 if( value == 0 )
315 {
316 regVal = regVal & ~obj->pinIndex;
317 }
318 else
319 {
320 regVal = regVal | obj->pinIndex;
321 }
322 SX1509Write( regAdd, regVal );
323 }
324
GpioIoeToggle(Gpio_t * obj)325 void GpioIoeToggle( Gpio_t *obj )
326 {
327 GpioIoeWrite( obj, GpioIoeRead( obj ) ^ 1 );
328 }
329
GpioIoeRead(Gpio_t * obj)330 uint32_t GpioIoeRead( Gpio_t *obj )
331 {
332 uint8_t regAdd = 0;
333 uint8_t regVal = 0;
334
335 if( ( obj->pin % 16 ) > 0x07 )
336 {
337 regAdd = RegDataB;
338 }
339 else
340 {
341 regAdd = RegDataA;
342 }
343
344 SX1509Read( regAdd, ®Val );
345
346 if( ( regVal & obj->pinIndex ) == 0x00 )
347 {
348 return 0;
349 }
350 else
351 {
352 return 1;
353 }
354 }
355
GpioIoeInterruptHandler(void)356 void GpioIoeInterruptHandler( void )
357 {
358 uint8_t irqLsb = 0;
359 uint8_t irqMsb = 0;
360 uint16_t irq = 0;
361
362 SX1509Read( RegInterruptSourceA, &irqLsb );
363 SX1509Read( RegInterruptSourceB, &irqMsb );
364
365 irq = ( irqMsb << 8 ) | irqLsb;
366 if( irq != 0x00 )
367 {
368 for( uint16_t mask = 0x0001, pinIndex = 0; mask != 0x000; mask <<= 1, pinIndex++ )
369 {
370 if( ( irq & mask ) != 0 )
371 {
372 if( ( GpioIrq[pinIndex] != NULL ) && ( GpioIrq[pinIndex]->IrqHandler != NULL ) )
373 {
374 GpioIrq[pinIndex]->IrqHandler( GpioIrq[pinIndex]->Context );
375 }
376 }
377 }
378 }
379
380 // Clear all interrupts/events
381 SX1509Write( RegInterruptSourceA, 0xFF );
382 SX1509Write( RegInterruptSourceB, 0xFF );
383 SX1509Write( RegEventStatusB, 0xFF );
384 SX1509Write( RegEventStatusA, 0xFF );
385 }
386