Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer


/*
 * Copyright (c) 2013 Sughosh Ganu
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce this list of conditions
 *    and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "opt_omapl1x.h"

#include <sys/cdefs.h>

__KERNEL_RCSID(0, "$NetBSD: omapl1x_psc.c,v 1.1 2013/10/02 16:48:26 matt Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/bus.h>

#include <arm/omap/omap_tipb.h>
#include <arm/omap/omapl1x_reg.h>
#include <arm/omap/omapl1x_misc.h>

typedef struct omapl1xpsc_softc {
	bus_space_tag_t		sc_iot;		/* Bus tag */
	bus_addr_t		sc_addr;	/* Address */
	bus_space_handle_t	sc_ioh;
	bus_size_t		sc_size;
	int			sc_unit;
} omapl1xpsc_softc_t;

/*
 * Currently, using only psc1 module, so
 * a single softc pointer should suffice.
*/
static omapl1xpsc_softc_t *sc;

static uint8_t omapl1x_lpsc_set_state(uint32_t state, uint32_t module);
static int omapl1xpsc_match(struct device *parent, struct cfdata *cf, void *aux);
static void omapl1xpsc_attach(device_t parent, device_t self, void *aux);

#define MDCTL_NEXT_MASK		0x7
#define MODULE_STATE		0x3f
#define LPSC_STATE_ENABLE	0x3

#define PSC1_USB20_MODULE	0x1
#define PSC1_USB11_MODULE	0x2

CFATTACH_DECL_NEW(omapl1xpsc, sizeof(struct omapl1xpsc_softc),
    omapl1xpsc_match, omapl1xpsc_attach, NULL, NULL);

static uint8_t
omapl1x_lpsc_set_state(uint32_t state, uint32_t module)
{
	uint32_t val;

	/* Wait for the GOSTAT[x] bit in PTSTAT to clear */
	do {
		val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PTSTAT);
	} while (val & 0x1);

	/* Set the Next bit in MDCTL to the state */
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
			       MDCTL + module * 4);
	val &= ~MDCTL_NEXT_MASK;
	val |= state;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MDCTL + module * 4, val);

	/* Set the GO bit in PTCMD to initiate the transition */
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PTCMD);
	val |= 0x1;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PTCMD, val);

	/* Wait for the GOSTAT[x] bit in PTSTAT to clear */
	do {
		val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PTSTAT);
	} while (val & 0x1);

	/* Check if the STATE field in MDSTAT reflects the new state */
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MDSTAT + module * 4);

	return (val & MODULE_STATE) != state ? 1 : 0;
}

uint8_t
omapl1x_lpsc_enable(uint32_t module)
{
	return omapl1x_lpsc_set_state(LPSC_STATE_ENABLE, module);
}

static int
omapl1xpsc_match(struct device *parent, struct cfdata *cf, void *aux)
{
	return 1;	/* XXX */
}

static void
omapl1xpsc_attach(device_t parent, device_t self, void *aux)
{
	struct tipb_attach_args *tipb = aux;

	sc = device_private(self);

	sc->sc_iot = tipb->tipb_iot;
	sc->sc_unit = self->dv_unit;
	sc->sc_addr = tipb->tipb_addr;
	sc->sc_size = tipb->tipb_size;

	/* Map PSC registers */
	if (bus_space_map(sc->sc_iot, sc->sc_addr, sc->sc_size,
			  0, &sc->sc_ioh)) {
		aprint_error_dev(self, "can't map psc%d mem space\n",
				 sc->sc_unit);
		return;
	}
}