chiark / gitweb /
Added in the SN3218 LED controller IC - as used in the PiGlow
[wiringPi.git] / wiringPi / mcp23s17.c
1 /*
2  * mcp23s17.c:
3  *      Extend wiringPi with the MCP 23s17 SPI GPIO expander chip
4  *      Copyright (c) 2013 Gordon Henderson
5  ***********************************************************************
6  * This file is part of wiringPi:
7  *      https://projects.drogon.net/raspberry-pi/wiringpi/
8  *
9  *    wiringPi is free software: you can redistribute it and/or modify
10  *    it under the terms of the GNU Lesser General Public License as
11  *    published by the Free Software Foundation, either version 3 of the
12  *    License, or (at your option) any later version.
13  *
14  *    wiringPi is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *    GNU Lesser General Public License for more details.
18  *
19  *    You should have received a copy of the GNU Lesser General Public
20  *    License along with wiringPi.
21  *    If not, see <http://www.gnu.org/licenses/>.
22  ***********************************************************************
23  */
24
25 #include <stdio.h>
26 #include <stdint.h>
27
28 #include "wiringPi.h"
29 #include "wiringPiSPI.h"
30 #include "mcp23x0817.h"
31
32 #include "mcp23s17.h"
33
34 #define MCP_SPEED       4000000
35
36
37
38 /*
39  * writeByte:
40  *      Write a byte to a register on the MCP23s17 on the SPI bus.
41  *********************************************************************************
42  */
43
44 static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data)
45 {
46   uint8_t spiData [4] ;
47
48   spiData [0] = CMD_WRITE | ((devId & 7) << 1) ;
49   spiData [1] = reg ;
50   spiData [2] = data ;
51
52   wiringPiSPIDataRW (spiPort, spiData, 3) ;
53 }
54
55 /*
56  * readByte:
57  *      Read a byte from a register on the MCP23s17 on the SPI bus.
58  *********************************************************************************
59  */
60
61 static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg)
62 {
63   uint8_t spiData [4] ;
64
65   spiData [0] = CMD_READ | ((devId & 7) << 1) ;
66   spiData [1] = reg ;
67
68   wiringPiSPIDataRW (spiPort, spiData, 3) ;
69
70   return spiData [2] ;
71 }
72
73
74 /*
75  * myPinMode:
76  *********************************************************************************
77  */
78
79 static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode)
80 {
81   int mask, old, reg ;
82
83   pin -= node->pinBase ;
84
85   if (pin < 8)          // Bank A
86     reg  = MCP23x17_IODIRA ;
87   else
88   {
89     reg  = MCP23x17_IODIRB ;
90     pin &= 0x07 ;
91   }
92
93   mask = 1 << pin ;
94   old  = readByte (node->data0, node->data1, reg) ;
95
96   if (mode == OUTPUT)
97     old &= (~mask) ;
98   else
99     old |=   mask ;
100
101   writeByte (node->data0, node->data1, reg, old) ;
102 }
103
104
105 /*
106  * myPullUpDnControl:
107  *********************************************************************************
108  */
109
110 static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode)
111 {
112   int mask, old, reg ;
113
114   pin -= node->pinBase ;
115
116   if (pin < 8)          // Bank A
117     reg  = MCP23x17_GPPUA ;
118   else
119   {
120     reg  = MCP23x17_GPPUB ;
121     pin &= 0x07 ;
122   }
123
124   mask = 1 << pin ;
125   old  = readByte (node->data0, node->data1, reg) ;
126
127   if (mode == PUD_UP)
128     old |=   mask ;
129   else
130     old &= (~mask) ;
131
132   writeByte (node->data0, node->data1, reg, old) ;
133 }
134
135
136 /*
137  * myDigitalWrite:
138  *********************************************************************************
139  */
140
141 static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value)
142 {
143   int bit, old ;
144
145   pin -= node->pinBase ;        // Pin now 0-15
146
147   bit = 1 << (pin & 7) ;
148
149   if (pin < 8)                  // Bank A
150   {
151     old = node->data2 ;
152
153     if (value == LOW)
154       old &= (~bit) ;
155     else
156       old |=   bit ;
157
158     writeByte (node->data0, node->data1, MCP23x17_GPIOA, old) ;
159     node->data2 = old ;
160   }
161   else                          // Bank B
162   {
163     old = node->data3 ;
164
165     if (value == LOW)
166       old &= (~bit) ;
167     else
168       old |=   bit ;
169
170     writeByte (node->data0, node->data1, MCP23x17_GPIOB, old) ;
171     node->data3 = old ;
172   }
173 }
174
175
176 /*
177  * myDigitalRead:
178  *********************************************************************************
179  */
180
181 static int myDigitalRead (struct wiringPiNodeStruct *node, int pin)
182 {
183   int mask, value, gpio ;
184
185   pin -= node->pinBase ;
186
187   if (pin < 8)          // Bank A
188     gpio  = MCP23x17_GPIOA ;
189   else
190   {
191     gpio  = MCP23x17_GPIOB ;
192     pin  &= 0x07 ;
193   }
194
195   mask  = 1 << pin ;
196   value = readByte (node->data0, node->data1, gpio) ;
197
198   if ((value & mask) == 0)
199     return LOW ;
200   else 
201     return HIGH ;
202 }
203
204
205 /*
206  * mcp23s17Setup:
207  *      Create a new instance of an MCP23s17 SPI GPIO interface. We know it
208  *      has 16 pins, so all we need to know here is the SPI address and the
209  *      user-defined pin base.
210  *********************************************************************************
211  */
212
213 int mcp23s17Setup (const int pinBase, const int spiPort, const int devId)
214 {
215   int    x ;
216   struct wiringPiNodeStruct *node ;
217
218   if ((x = wiringPiSPISetup (spiPort, MCP_SPEED)) < 0)
219     return x ;
220
221   writeByte (spiPort, devId, MCP23x17_IOCON,  IOCON_INIT | IOCON_HAEN) ;
222   writeByte (spiPort, devId, MCP23x17_IOCONB, IOCON_INIT | IOCON_HAEN) ;
223
224   node = wiringPiNewNode (pinBase, 16) ;
225
226   node->data0           = spiPort ;
227   node->data1           = devId ;
228   node->pinMode         = myPinMode ;
229   node->pullUpDnControl = myPullUpDnControl ;
230   node->digitalRead     = myDigitalRead ;
231   node->digitalWrite    = myDigitalWrite ;
232   node->data2           = readByte (spiPort, devId, MCP23x17_OLATA) ;
233   node->data3           = readByte (spiPort, devId, MCP23x17_OLATB) ;
234
235   return 0 ;
236 }