initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / sitara_cm.c
CommitLineData
cf3c20ae 1/* $OpenBSD: sitara_cm.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
2/* $NetBSD: sitara_cm.c,v 1.1 2013/04/17 14:31:02 bouyer Exp $ */
3/*
4 * Copyright (c) 2010
5 * Ben Gray <ben.r.gray@gmail.com>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Ben Gray.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * SCM - System Control Module
37 *
38 * Hopefully in the end this module will contain a bunch of utility functions
39 * for configuring and querying the general system control registers, but for
40 * now it only does pin(pad) multiplexing.
41 *
42 * This is different from the GPIO module in that it is used to configure the
43 * pins between modules not just GPIO input/output.
44 *
45 * This file contains the generic top level driver, however it relies on chip
46 * specific settings and therefore expects an array of sitara_cm_padconf structs
47 * call ti_padconf_devmap to be located somewhere in the kernel.
48 *
49 */
50#include <sys/types.h>
51#include <sys/cdefs.h>
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/kernel.h>
55#include <sys/device.h>
56#include <sys/conf.h>
57#include <sys/proc.h>
58#include <machine/bus.h>
59
60#include <armv7/armv7/armv7var.h>
61#include <armv7/omap/sitara_cm.h>
62#include <armv7/omap/sitara_cmreg.h>
63
64void sitara_cm_attach(struct device *parent, struct device *self, void *aux);
65
66struct sitara_cm_softc {
67 struct device sc_dev;
68 bus_space_tag_t sc_iot;
69 bus_space_handle_t sc_ioh;
70};
71
72struct cfattach sitaracm_ca = {
73 sizeof (struct sitara_cm_softc), NULL, sitara_cm_attach
74};
75
76struct cfdriver sitaracm_cd = {
77 NULL, "sitaracm", DV_DULL
78};
79
80static struct sitara_cm_softc *sitara_cm_sc = NULL;
81
82#define sitara_cm_read_2(sc, reg) \
83 bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))
84#define sitara_cm_write_2(sc, reg, val) \
85 bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
86#define sitara_cm_read_4(sc, reg) \
87 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
88#define sitara_cm_write_4(sc, reg, val) \
89 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
90
91
92/**
93 * ti_padconf_devmap - Array of pins, should be defined one per SoC
94 *
95 * This array is typically defined in one of the targeted *_scm_pinumx.c
96 * files and is specific to the given SoC platform. Each entry in the array
97 * corresponds to an individual pin.
98 */
99extern const struct sitara_cm_device sitara_cm_dev;
100
101
102/**
103 * sitara_cm_padconf_from_name - searches the list of pads and returns entry
104 * with matching ball name.
105 * @ballname: the name of the ball
106 *
107 * RETURNS:
108 * A pointer to the matching padconf or NULL if the ball wasn't found.
109 */
110static const struct sitara_cm_padconf*
111sitara_cm_padconf_from_name(const char *ballname)
112{
113 const struct sitara_cm_padconf *padconf;
114
115 padconf = sitara_cm_dev.padconf;
116 while (padconf->ballname != NULL) {
117 if (strcmp(ballname, padconf->ballname) == 0)
118 return(padconf);
119 padconf++;
120 }
121
122 return (NULL);
123}
124
125/**
126 * sitara_cm_padconf_set_internal - sets the muxmode and state for a pad/pin
127 * @padconf: pointer to the pad structure
128 * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
129 * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
130 *
131 *
132 * LOCKING:
133 * Internally locks it's own context.
134 *
135 * RETURNS:
136 * 0 on success.
137 * EINVAL if pin requested is outside valid range or already in use.
138 */
139static int
140sitara_cm_padconf_set_internal(struct sitara_cm_softc *sc,
141 const struct sitara_cm_padconf *padconf,
142 const char *muxmode, unsigned int state)
143{
144 unsigned int mode;
145 uint16_t reg_val;
146
147 /* populate the new value for the PADCONF register */
148 reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask);
149
150 /* find the new mode requested */
151 for (mode = 0; mode < 8; mode++) {
152 if ((padconf->muxmodes[mode] != NULL) &&
153 (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
154 break;
155 }
156 }
157
158 /* couldn't find the mux mode */
159 if (mode >= 8) {
160 printf("%s: Invalid mux mode \"%s\"\n", __func__, muxmode);
161 return (EINVAL);
162 }
163
164 /* set the mux mode */
165 reg_val |= (uint16_t)(mode & sitara_cm_dev.padconf_muxmode_mask);
166
167 /* write the register value (16-bit writes) */
168 sitara_cm_write_2(sc, padconf->reg_off, reg_val);
169
170 return (0);
171}
172
173/**
174 * sitara_cm_padconf_set - sets the muxmode and state for a pad/pin
175 * @padname: the name of the pad, i.e. "c12"
176 * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
177 * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
178 *
179 *
180 * LOCKING:
181 * Internally locks it's own context.
182 *
183 * RETURNS:
184 * 0 on success.
185 * EINVAL if pin requested is outside valid range or already in use.
186 */
187int
188sitara_cm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
189{
190 const struct sitara_cm_padconf *padconf;
191
192 if (!sitara_cm_sc)
193 return (ENXIO);
194
195 /* find the pin in the devmap */
196 padconf = sitara_cm_padconf_from_name(padname);
197 if (padconf == NULL)
198 return (EINVAL);
199
200 return (
201 sitara_cm_padconf_set_internal(sitara_cm_sc, padconf, muxmode, state)
202 );
203}
204
205/**
206 * sitara_cm_padconf_get - gets the muxmode and state for a pad/pin
207 * @padname: the name of the pad, i.e. "c12"
208 * @muxmode: upon return will contain the name of the muxmode of the pin
209 * @state: upon return will contain the state of the pad/pin
210 *
211 *
212 * LOCKING:
213 * Internally locks it's own context.
214 *
215 * RETURNS:
216 * 0 on success.
217 * EINVAL if pin requested is outside valid range or already in use.
218 */
219int
220sitara_cm_padconf_get(const char *padname, const char **muxmode,
221 unsigned int *state)
222{
223 const struct sitara_cm_padconf *padconf;
224 uint16_t reg_val;
225
226 if (!sitara_cm_sc)
227 return (ENXIO);
228
229 /* find the pin in the devmap */
230 padconf = sitara_cm_padconf_from_name(padname);
231 if (padconf == NULL)
232 return (EINVAL);
233
234 /* read the register value (16-bit reads) */
235 reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off);
236
237 /* save the state */
238 if (state)
239 *state = (reg_val & sitara_cm_dev.padconf_sate_mask);
240
241 /* save the mode */
242 if (muxmode) {
243 *muxmode = padconf->muxmodes[
244 (reg_val & sitara_cm_dev.padconf_muxmode_mask)
245 ];
246 }
247
248 return (0);
249}
250
251/**
252 * sitara_cm_padconf_set_gpiomode - converts a pad to GPIO mode.
253 * @gpio: the GPIO pin number (0-195)
254 * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
255 *
256 *
257 *
258 * LOCKING:
259 * Internally locks it's own context.
260 *
261 * RETURNS:
262 * 0 on success.
263 * EINVAL if pin requested is outside valid range or already in use.
264 */
265int
266sitara_cm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
267{
268 const struct sitara_cm_padconf *padconf;
269 uint16_t reg_val;
270
271 if (!sitara_cm_sc)
272 return (ENXIO);
273
274 /* find the gpio pin in the padconf array */
275 padconf = sitara_cm_dev.padconf;
276 while (padconf->ballname != NULL) {
277 if (padconf->gpio_pin == gpio)
278 break;
279 padconf++;
280 }
281 if (padconf->ballname == NULL)
282 return (EINVAL);
283
284 /* populate the new value for the PADCONF register */
285 reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask);
286
287 /* set the mux mode */
288 reg_val |=
289 (uint16_t)(padconf->gpio_mode & sitara_cm_dev.padconf_muxmode_mask);
290
291 /* write the register value (16-bit writes) */
292 sitara_cm_write_2(sitara_cm_sc, padconf->reg_off, reg_val);
293
294 return (0);
295}
296
297/**
298 * sitara_cm_padconf_get_gpiomode - gets the current GPIO mode of the pin
299 * @gpio: the GPIO pin number (0-195)
300 * @state: upon return will contain the state
301 *
302 *
303 *
304 * LOCKING:
305 * Internally locks it's own context.
306 *
307 * RETURNS:
308 * 0 on success.
309 * EINVAL if pin requested is outside valid range or not configured as GPIO.
310 */
311int
312sitara_cm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
313{
314 const struct sitara_cm_padconf *padconf;
315 uint16_t reg_val;
316
317 if (!sitara_cm_sc)
318 return (ENXIO);
319
320 /* find the gpio pin in the padconf array */
321 padconf = sitara_cm_dev.padconf;
322 while (padconf->ballname != NULL) {
323 if (padconf->gpio_pin == gpio)
324 break;
325 padconf++;
326 }
327 if (padconf->ballname == NULL)
328 return (EINVAL);
329
330 /* read the current register settings */
331 reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off);
332
333 /*
334 * check to make sure the pins is configured as GPIO in the
335 * first state
336 */
337 if ((reg_val & sitara_cm_dev.padconf_muxmode_mask) !=
338 padconf->gpio_mode)
339 return (EINVAL);
340
341 /*
342 * read and store the reset of the state,
343 * i.e. pull-up, pull-down, etc
344 */
345 if (state)
346 *state = (reg_val & sitara_cm_dev.padconf_sate_mask);
347
348 return (0);
349}
350
351
352int
353sitara_cm_reg_read_4(uint32_t reg, uint32_t *val)
354{
355 if (!sitara_cm_sc)
356 return (ENXIO);
357
358 *val = sitara_cm_read_4(sitara_cm_sc, reg);
359 return (0);
360}
361
362int
363sitara_cm_reg_write_4(uint32_t reg, uint32_t val)
364{
365 if (!sitara_cm_sc)
366 return (ENXIO);
367
368 sitara_cm_write_4(sitara_cm_sc, reg, val);
369 return (0);
370}
371
372void
373sitara_cm_attach(struct device *parent, struct device *self, void *aux)
374{
375 struct sitara_cm_softc *sc = (struct sitara_cm_softc *)self;
376 struct armv7_attach_args *aa = aux;
377 uint32_t rev;
378
379 if (sitara_cm_sc)
380 panic("sitara_cm_attach: already attached");
381
382 sc->sc_iot = aa->aa_iot;
383
384 if (bus_space_map(aa->aa_iot, aa->aa_dev->mem[0].addr,
385 aa->aa_dev->mem[0].size, 0, &sc->sc_ioh) != 0)
386 panic("%s: bus_space_map failed!\n", __func__);
387
388 sitara_cm_sc = sc;
389
390 if (sitara_cm_reg_read_4(OMAP2SCM_REVISION, &rev) != 0)
391 panic("sitara_cm_attach: read revision");
392 printf(": control module, rev %d.%d\n",
393 SCM_REVISION_MAJOR(rev), SCM_REVISION_MINOR(rev));
394}