c57a07683352f7170992080479c431592474cb46
[pinmux.git] / src / spec / interfaces.py
1 #!/usr/bin/env python
2
3 from spec.pinfunctions import pinspec
4 from copy import deepcopy
5
6
7 def namesuffix(name, suffix, namelist):
8 names = []
9 for n in namelist:
10 if n:
11 names.append("%s%s_%s" % (name, suffix, n))
12 else:
13 names.append("%s_%s" % (name, suffix))
14 return names
15
16
17 class PinGen(object):
18 """ a meta-helper which creates pins from the pinspec
19 and adds them to the pinouts.
20
21 __call__ is used to effectively create a lambda function, which
22 in combination with setattr (below) gives the function a name
23 in the Pinouts class, according to the pinspec.
24
25 arguments to __call__ (which ends up as Pinouts.i2s, Pinouts.sdmmc
26 and so on, according to spec.pinfunctions.pinspec) are:
27
28 suffix: e.g. GPIO or SD or SPI
29 offs : a tuple of (Bank, Bank offset) as a string, integer
30 mux : which column in the multiplexer
31 start : the start of a subset of pins to be inserted
32 limit : the end of the subset (or the number if start also given)
33 spec : *EXTRA* pins to be inserted.
34
35 spec is slightly complicated, basically there's extra
36 functions that we want to be on the same pin (but a different mux)
37 because their use is mutually-exclusive. without this spec
38 argument the extra pins would need to be MANUALLY moved about
39 during the development of the pinmux, if the "main" pins
40 were also moved about. this would be a pain.
41
42 so instead, extra pins are given of the form:
43 { 'EXTRA1' : ('PREEXISTING_NAME', MUX_COLUMN),
44 ...
45 }
46
47 where the function EXTRA1 will always be placed on the SAME ROW
48 as PREEXISTING_NAME, just in MUX_COLUMN. this may be done
49 several times i.e. multiple new EXTRA functions can be added
50 on the same row as PRE_EXISTING_NAME, just with different
51 MUX_COLUMN values.
52
53 Note: spec must implicitly be in the same Bank.
54 """
55
56 def __init__(self, pinouts, fname, pinfn, bankspec):
57 self.pinouts = pinouts
58 self.bankspec = bankspec
59 self.pinfn = pinfn
60 self.fname = fname
61
62 def __call__(self, suffix, offs, mux,
63 start=None, limit=None, spec=None, origsuffix=None):
64 bank = offs[0]
65 pingroup, gangedgroup = self.pinfn(suffix, bank)
66 if isinstance(pingroup, tuple):
67 prefix, pingroup = pingroup
68 else:
69 prefix = self.fname
70 if start and limit: # limit turns into an offset from start
71 limit = start + limit
72 pingroup = pingroup[start:limit] # see comment in spec.pinfunctions
73 pins = Pins(prefix, pingroup, self.bankspec,
74 suffix, offs, bank, mux,
75 spec, origsuffix=suffix, gangedgrp=gangedgroup)
76 self.pinouts.pinmerge(pins)
77
78 # pinouts class
79
80
81 class Pinouts(object):
82 def __init__(self, bankspec):
83 self.bankspec = bankspec
84 self.pins = {}
85 self.fnspec = {}
86 for fname, pinfn in pinspec:
87 if isinstance(pinfn, tuple):
88 name, pinfn = pinfn
89 else:
90 name = pinfn.__name__
91 setattr(self, name, PinGen(self, fname, pinfn, self.bankspec))
92
93 def __contains__(self, k):
94 return k in self.pins
95
96 def has_key(self, k):
97 return k in self.pins
98
99 def add_spec(self, k, v):
100 self.fnspec[k] = v
101
102 def update(self, pinidx, v):
103 if pinidx not in self.pins:
104 self.pins[pinidx] = v
105 else:
106 for k in v:
107 assert k not in self.pins[pinidx], \
108 "pin %d position %d already taken\n%s\n%s" % \
109 (pinidx, k, str(v), self.pins[pinidx])
110 self.pins[pinidx].update(v)
111
112 def keys(self):
113 return self.pins.keys()
114
115 def items(self):
116 return self.pins.items()
117
118 def get(self, k):
119 return self.pins[k]
120
121 def __len__(self):
122 return len(self.pins)
123
124 def __delitem__(self, k):
125 del self.pins[k]
126
127 def __getitem__(self, k):
128 return self.pins[k]
129
130 def pinmerge(self, fn):
131 # hack, store the function specs in the pins dict
132 fname = fn.fname
133 suffix = fn.origsuffix
134 bank = fn.bank
135
136 if not hasattr(self, 'fnspec'):
137 self.fnspec = pins
138 if fname == 'GPIO':
139 fname = fname + bank
140 assert 'EINT' not in self
141 if fname not in self.fnspec:
142 self.add_spec(fname, {})
143 if suffix or fname == 'EINT' or fname == 'PWM':
144 specname = fname + suffix
145 else:
146 specname = fname
147 # print "fname bank specname suffix ", fname, bank, specname, repr(
148 # suffix)
149 if specname in self.fnspec[fname]:
150 # ok so some declarations may bring in different
151 # names at different stages (EINT, PWM, flexbus1/2)
152 # so we have to merge the names in. main thing is
153 # the pingroup
154 tomerge = self.fnspec[fname][specname]
155 for p in fn.pingroup:
156 if p not in tomerge.pingroup:
157 tomerge.pingroup.append(p)
158 tomerge.pins.update(fn.pins)
159 tomerge.fntype.update(fn.fntype)
160 else:
161 self.fnspec[fname][specname] = deepcopy(fn)
162
163 # merge actual pins
164 for (pinidx, v) in fn.pins.items():
165 self.update(pinidx, v)
166
167
168 class Pins(object):
169
170 def __init__(self, fname, pingroup, bankspec, suffix, offs, bank, mux,
171 spec=None, limit=None, origsuffix=None, gangedgrp=None):
172
173 # function type can be in, out or inout, represented by - + *
174 # strip function type out of each pin name
175 self.fntype = {}
176 for i in range(len(pingroup)):
177 pname = pingroup[i]
178 if not pname:
179 continue
180 fntype = pname[-1]
181 if fntype not in '+-*':
182 continue
183 pname = pname[:-1]
184 fntype = {'-': 'in', '+': 'out', '*': 'inout'}[fntype]
185 self.fntype[pname] = fntype
186 pingroup[i] = pname
187
188 self.fname = fname
189 self.pingroup = pingroup
190 self.gangedgroup = gangedgrp
191 self.bankspec = bankspec
192 self.suffix = suffix
193 self.origsuffix = origsuffix or suffix
194 self.bank = bank
195 self.mux = mux
196
197 # create consistent name suffixes
198 pingroup = namesuffix(fname, suffix, pingroup)
199 suffix = '' # hack
200
201 res = {}
202 names = {}
203 idx = 0
204 for name in pingroup[:limit]:
205 if suffix and name:
206 name_ = "%s_%s" % (name, suffix)
207 else:
208 name_ = name
209 if spec and name in spec:
210 continue
211 pin = {mux: (name_, bank)}
212 offs_bank, offs_ = offs
213 idx_ = offs_ + idx
214 idx += 1
215 idx_ += bankspec[bank]
216 res[idx_] = pin
217 names[name] = idx_
218 for name in pingroup:
219 if suffix and name:
220 name_ = "%s_%s" % (name, suffix)
221 else:
222 name_ = name
223 if not spec:
224 continue
225 if name not in spec:
226 continue
227 idx_, mux_ = spec[name]
228 idx_ = names[idx_]
229 pin = {mux_: (name_, bank)}
230 if idx_ in res:
231 res[idx_].update(pin)
232 else:
233 res[idx_] = pin
234
235 self.pins = res