Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/ti/ti_pinmux.c
39481 views
1
/*
2
* Copyright (c) 2010
3
* Ben Gray <[email protected]>.
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. All advertising materials mentioning features or use of this software
15
* must display the following acknowledgement:
16
* This product includes software developed by Ben Gray.
17
* 4. The name of the company nor the name of the author may be used to
18
* endorse or promote products derived from this software without specific
19
* prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
22
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24
* IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
/**
34
* Exposes pinmux module to pinctrl-compatible interface
35
*/
36
37
#include <sys/param.h>
38
#include <sys/systm.h>
39
#include <sys/kernel.h>
40
#include <sys/module.h>
41
#include <sys/bus.h>
42
#include <sys/resource.h>
43
#include <sys/rman.h>
44
#include <sys/lock.h>
45
#include <sys/mutex.h>
46
47
#include <machine/bus.h>
48
#include <machine/resource.h>
49
50
#include <dev/ofw/openfirm.h>
51
#include <dev/ofw/ofw_bus.h>
52
#include <dev/ofw/ofw_bus_subr.h>
53
#include <dev/fdt/fdt_pinctrl.h>
54
55
#include <arm/ti/am335x/am335x_scm_padconf.h>
56
#include <arm/ti/ti_cpuid.h>
57
#include "ti_pinmux.h"
58
59
struct pincfg {
60
uint32_t reg;
61
uint32_t conf;
62
};
63
64
static struct resource_spec ti_pinmux_res_spec[] = {
65
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */
66
{ -1, 0 }
67
};
68
69
static struct ti_pinmux_softc *ti_pinmux_sc;
70
71
#define ti_pinmux_read_2(sc, reg) \
72
bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
73
#define ti_pinmux_write_2(sc, reg, val) \
74
bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
75
#define ti_pinmux_read_4(sc, reg) \
76
bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
77
#define ti_pinmux_write_4(sc, reg, val) \
78
bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
79
80
/**
81
* ti_padconf_devmap - Array of pins, should be defined one per SoC
82
*
83
* This array is typically defined in one of the targeted *_scm_pinumx.c
84
* files and is specific to the given SoC platform. Each entry in the array
85
* corresponds to an individual pin.
86
*/
87
static const struct ti_pinmux_device *ti_pinmux_dev;
88
89
/**
90
* ti_pinmux_padconf_from_name - searches the list of pads and returns entry
91
* with matching ball name.
92
* @ballname: the name of the ball
93
*
94
* RETURNS:
95
* A pointer to the matching padconf or NULL if the ball wasn't found.
96
*/
97
static const struct ti_pinmux_padconf*
98
ti_pinmux_padconf_from_name(const char *ballname)
99
{
100
const struct ti_pinmux_padconf *padconf;
101
102
padconf = ti_pinmux_dev->padconf;
103
while (padconf->ballname != NULL) {
104
if (strcmp(ballname, padconf->ballname) == 0)
105
return(padconf);
106
padconf++;
107
}
108
109
return (NULL);
110
}
111
112
/**
113
* ti_pinmux_padconf_set_internal - sets the muxmode and state for a pad/pin
114
* @padconf: pointer to the pad structure
115
* @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
116
* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
117
*
118
*
119
* LOCKING:
120
* Internally locks it's own context.
121
*
122
* RETURNS:
123
* 0 on success.
124
* EINVAL if pin requested is outside valid range or already in use.
125
*/
126
static int
127
ti_pinmux_padconf_set_internal(struct ti_pinmux_softc *sc,
128
const struct ti_pinmux_padconf *padconf,
129
const char *muxmode, unsigned int state)
130
{
131
unsigned int mode;
132
uint16_t reg_val;
133
134
/* populate the new value for the PADCONF register */
135
reg_val = (uint16_t)(state & ti_pinmux_dev->padconf_sate_mask);
136
137
/* find the new mode requested */
138
for (mode = 0; mode < 8; mode++) {
139
if ((padconf->muxmodes[mode] != NULL) &&
140
(strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
141
break;
142
}
143
}
144
145
/* couldn't find the mux mode */
146
if (mode >= 8) {
147
printf("Invalid mode \"%s\"\n", muxmode);
148
return (EINVAL);
149
}
150
151
/* set the mux mode */
152
reg_val |= (uint16_t)(mode & ti_pinmux_dev->padconf_muxmode_mask);
153
154
if (bootverbose)
155
device_printf(sc->sc_dev, "setting internal %x for %s\n",
156
reg_val, muxmode);
157
/* write the register value (16-bit writes) */
158
ti_pinmux_write_2(sc, padconf->reg_off, reg_val);
159
160
return (0);
161
}
162
163
/**
164
* ti_pinmux_padconf_set - sets the muxmode and state for a pad/pin
165
* @padname: the name of the pad, i.e. "c12"
166
* @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
167
* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
168
*
169
*
170
* LOCKING:
171
* Internally locks it's own context.
172
*
173
* RETURNS:
174
* 0 on success.
175
* EINVAL if pin requested is outside valid range or already in use.
176
*/
177
int
178
ti_pinmux_padconf_set(const char *padname, const char *muxmode, unsigned int state)
179
{
180
const struct ti_pinmux_padconf *padconf;
181
182
if (!ti_pinmux_sc)
183
return (ENXIO);
184
185
/* find the pin in the devmap */
186
padconf = ti_pinmux_padconf_from_name(padname);
187
if (padconf == NULL)
188
return (EINVAL);
189
190
return (ti_pinmux_padconf_set_internal(ti_pinmux_sc, padconf, muxmode, state));
191
}
192
193
/**
194
* ti_pinmux_padconf_get - gets the muxmode and state for a pad/pin
195
* @padname: the name of the pad, i.e. "c12"
196
* @muxmode: upon return will contain the name of the muxmode of the pin
197
* @state: upon return will contain the state of the pad/pin
198
*
199
*
200
* LOCKING:
201
* Internally locks it's own context.
202
*
203
* RETURNS:
204
* 0 on success.
205
* EINVAL if pin requested is outside valid range or already in use.
206
*/
207
int
208
ti_pinmux_padconf_get(const char *padname, const char **muxmode,
209
unsigned int *state)
210
{
211
const struct ti_pinmux_padconf *padconf;
212
uint16_t reg_val;
213
214
if (!ti_pinmux_sc)
215
return (ENXIO);
216
217
/* find the pin in the devmap */
218
padconf = ti_pinmux_padconf_from_name(padname);
219
if (padconf == NULL)
220
return (EINVAL);
221
222
/* read the register value (16-bit reads) */
223
reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off);
224
225
/* save the state */
226
if (state)
227
*state = (reg_val & ti_pinmux_dev->padconf_sate_mask);
228
229
/* save the mode */
230
if (muxmode)
231
*muxmode = padconf->muxmodes[(reg_val & ti_pinmux_dev->padconf_muxmode_mask)];
232
233
return (0);
234
}
235
236
/**
237
* ti_pinmux_padconf_set_gpiomode - converts a pad to GPIO mode.
238
* @gpio: the GPIO pin number (0-195)
239
* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
240
*
241
*
242
*
243
* LOCKING:
244
* Internally locks it's own context.
245
*
246
* RETURNS:
247
* 0 on success.
248
* EINVAL if pin requested is outside valid range or already in use.
249
*/
250
int
251
ti_pinmux_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
252
{
253
const struct ti_pinmux_padconf *padconf;
254
uint16_t reg_val;
255
256
if (!ti_pinmux_sc)
257
return (ENXIO);
258
259
/* find the gpio pin in the padconf array */
260
padconf = ti_pinmux_dev->padconf;
261
while (padconf->ballname != NULL) {
262
if (padconf->gpio_pin == gpio)
263
break;
264
padconf++;
265
}
266
if (padconf->ballname == NULL)
267
return (EINVAL);
268
269
/* populate the new value for the PADCONF register */
270
reg_val = (uint16_t)(state & ti_pinmux_dev->padconf_sate_mask);
271
272
/* set the mux mode */
273
reg_val |= (uint16_t)(padconf->gpio_mode & ti_pinmux_dev->padconf_muxmode_mask);
274
275
/* write the register value (16-bit writes) */
276
ti_pinmux_write_2(ti_pinmux_sc, padconf->reg_off, reg_val);
277
278
return (0);
279
}
280
281
/**
282
* ti_pinmux_padconf_get_gpiomode - gets the current GPIO mode of the pin
283
* @gpio: the GPIO pin number (0-195)
284
* @state: upon return will contain the state
285
*
286
*
287
*
288
* LOCKING:
289
* Internally locks it's own context.
290
*
291
* RETURNS:
292
* 0 on success.
293
* EINVAL if pin requested is outside valid range or not configured as GPIO.
294
*/
295
int
296
ti_pinmux_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
297
{
298
const struct ti_pinmux_padconf *padconf;
299
uint16_t reg_val;
300
301
if (!ti_pinmux_sc)
302
return (ENXIO);
303
304
/* find the gpio pin in the padconf array */
305
padconf = ti_pinmux_dev->padconf;
306
while (padconf->ballname != NULL) {
307
if (padconf->gpio_pin == gpio)
308
break;
309
padconf++;
310
}
311
if (padconf->ballname == NULL)
312
return (EINVAL);
313
314
/* read the current register settings */
315
reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off);
316
317
/* check to make sure the pins is configured as GPIO in the first state */
318
if ((reg_val & ti_pinmux_dev->padconf_muxmode_mask) != padconf->gpio_mode)
319
return (EINVAL);
320
321
/* read and store the reset of the state, i.e. pull-up, pull-down, etc */
322
if (state)
323
*state = (reg_val & ti_pinmux_dev->padconf_sate_mask);
324
325
return (0);
326
}
327
328
static int
329
ti_pinmux_configure_pins(device_t dev, phandle_t cfgxref)
330
{
331
struct pincfg *cfgtuples, *cfg;
332
phandle_t cfgnode;
333
int i, ntuples;
334
static struct ti_pinmux_softc *sc;
335
336
sc = device_get_softc(dev);
337
cfgnode = OF_node_from_xref(cfgxref);
338
ntuples = OF_getencprop_alloc_multi(cfgnode, "pinctrl-single,pins",
339
sizeof(*cfgtuples), (void **)&cfgtuples);
340
341
if (ntuples < 0)
342
return (ENOENT);
343
344
if (ntuples == 0)
345
return (0); /* Empty property is not an error. */
346
347
for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) {
348
if (bootverbose) {
349
char name[32];
350
OF_getprop(cfgnode, "name", &name, sizeof(name));
351
printf("%16s: muxreg 0x%04x muxval 0x%02x\n",
352
name, cfg->reg, cfg->conf);
353
}
354
355
/* write the register value (16-bit writes) */
356
ti_pinmux_write_2(sc, cfg->reg, cfg->conf);
357
}
358
359
OF_prop_free(cfgtuples);
360
361
return (0);
362
}
363
364
/*
365
* Device part of OMAP SCM driver
366
*/
367
368
static int
369
ti_pinmux_probe(device_t dev)
370
{
371
if (!ofw_bus_status_okay(dev))
372
return (ENXIO);
373
374
if (!ofw_bus_is_compatible(dev, "pinctrl-single"))
375
return (ENXIO);
376
377
if (ti_pinmux_sc) {
378
printf("%s: multiple pinctrl modules in device tree data, ignoring\n",
379
__func__);
380
return (EEXIST);
381
}
382
switch (ti_chip()) {
383
#ifdef SOC_TI_AM335X
384
case CHIP_AM335X:
385
ti_pinmux_dev = &ti_am335x_pinmux_dev;
386
break;
387
#endif
388
default:
389
printf("Unknown CPU in pinmux\n");
390
return (ENXIO);
391
}
392
393
device_set_desc(dev, "TI Pinmux Module");
394
return (BUS_PROBE_DEFAULT);
395
}
396
397
/**
398
* ti_pinmux_attach - attaches the pinmux to the simplebus
399
* @dev: new device
400
*
401
* RETURNS
402
* Zero on success or ENXIO if an error occuried.
403
*/
404
static int
405
ti_pinmux_attach(device_t dev)
406
{
407
struct ti_pinmux_softc *sc = device_get_softc(dev);
408
409
#if 0
410
if (ti_pinmux_sc)
411
return (ENXIO);
412
#endif
413
414
sc->sc_dev = dev;
415
416
if (bus_alloc_resources(dev, ti_pinmux_res_spec, sc->sc_res)) {
417
device_printf(dev, "could not allocate resources\n");
418
return (ENXIO);
419
}
420
421
sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
422
sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
423
424
if (ti_pinmux_sc == NULL)
425
ti_pinmux_sc = sc;
426
427
fdt_pinctrl_register(dev, "pinctrl-single,pins");
428
fdt_pinctrl_configure_tree(dev);
429
430
return (0);
431
}
432
433
static device_method_t ti_pinmux_methods[] = {
434
DEVMETHOD(device_probe, ti_pinmux_probe),
435
DEVMETHOD(device_attach, ti_pinmux_attach),
436
437
/* fdt_pinctrl interface */
438
DEVMETHOD(fdt_pinctrl_configure, ti_pinmux_configure_pins),
439
{ 0, 0 }
440
};
441
442
static driver_t ti_pinmux_driver = {
443
"ti_pinmux",
444
ti_pinmux_methods,
445
sizeof(struct ti_pinmux_softc),
446
};
447
448
DRIVER_MODULE(ti_pinmux, simplebus, ti_pinmux_driver, 0, 0);
449
MODULE_VERSION(ti_pinmux, 1);
450
MODULE_DEPEND(ti_pinmux, ti_scm, 1, 1, 1);
451
452