1*c56890eeSmsaitoh /* $Id: imx23_digctl.c,v 1.2 2019/10/18 04:09:01 msaitoh Exp $ */
294de0730Smatt
394de0730Smatt /*
494de0730Smatt * Copyright (c) 2013 The NetBSD Foundation, Inc.
594de0730Smatt * All rights reserved.
694de0730Smatt *
794de0730Smatt * This code is derived from software contributed to The NetBSD Foundation
894de0730Smatt * by Petri Laakso.
994de0730Smatt *
1094de0730Smatt * Redistribution and use in source and binary forms, with or without
1194de0730Smatt * modification, are permitted provided that the following conditions
1294de0730Smatt * are met:
1394de0730Smatt * 1. Redistributions of source code must retain the above copyright
1494de0730Smatt * notice, this list of conditions and the following disclaimer.
1594de0730Smatt * 2. Redistributions in binary form must reproduce the above copyright
1694de0730Smatt * notice, this list of conditions and the following disclaimer in the
1794de0730Smatt * documentation and/or other materials provided with the distribution.
1894de0730Smatt *
1994de0730Smatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2094de0730Smatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2194de0730Smatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2294de0730Smatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2394de0730Smatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2494de0730Smatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2594de0730Smatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2694de0730Smatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2794de0730Smatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2894de0730Smatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2994de0730Smatt * POSSIBILITY OF SUCH DAMAGE.
3094de0730Smatt */
3194de0730Smatt
3294de0730Smatt #include <sys/param.h>
3394de0730Smatt #include <sys/types.h>
3494de0730Smatt #include <sys/bus.h>
3594de0730Smatt #include <sys/cdefs.h>
3694de0730Smatt #include <sys/device.h>
3794de0730Smatt #include <sys/errno.h>
3894de0730Smatt #include <sys/timetc.h>
3994de0730Smatt
4094de0730Smatt #include <arm/imx/imx23_digctlreg.h>
4194de0730Smatt #include <arm/imx/imx23_digctlvar.h>
4294de0730Smatt #include <arm/imx/imx23var.h>
4394de0730Smatt
4494de0730Smatt typedef struct digctl_softc {
4594de0730Smatt device_t sc_dev;
4694de0730Smatt bus_space_tag_t sc_iot;
4794de0730Smatt bus_space_handle_t sc_hdl;
4894de0730Smatt } *digctl_softc_t;
4994de0730Smatt
5094de0730Smatt static int digctl_match(device_t, cfdata_t, void *);
5194de0730Smatt static void digctl_attach(device_t, device_t, void *);
5294de0730Smatt static int digctl_activate(device_t, enum devact);
5394de0730Smatt
5494de0730Smatt static void digctl_reset(struct digctl_softc *);
5594de0730Smatt static void digctl_init(struct digctl_softc *);
5694de0730Smatt
5794de0730Smatt /* timecounter. */
5894de0730Smatt static u_int digctl_tc_get_timecount(struct timecounter *);
5994de0730Smatt
6094de0730Smatt static digctl_softc_t _sc = NULL;
6194de0730Smatt
6294de0730Smatt CFATTACH_DECL3_NEW(digctl,
6394de0730Smatt sizeof(struct digctl_softc),
6494de0730Smatt digctl_match,
6594de0730Smatt digctl_attach,
6694de0730Smatt NULL,
6794de0730Smatt digctl_activate,
6894de0730Smatt NULL,
6994de0730Smatt NULL,
7094de0730Smatt 0
7194de0730Smatt );
7294de0730Smatt
7394de0730Smatt static struct timecounter tc_useconds;
7494de0730Smatt
7594de0730Smatt #define DCTL_RD(sc, reg) \
7694de0730Smatt bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
7794de0730Smatt #define DCTL_WR(sc, reg, val) \
7894de0730Smatt bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
7994de0730Smatt
8094de0730Smatt static int
digctl_match(device_t parent,cfdata_t match,void * aux)8194de0730Smatt digctl_match(device_t parent, cfdata_t match, void *aux)
8294de0730Smatt {
8394de0730Smatt struct apb_attach_args *aa = aux;
8494de0730Smatt
8594de0730Smatt if ((aa->aa_addr == HW_DIGCTL_BASE) && (aa->aa_size == HW_DIGCTL_SIZE))
8694de0730Smatt return 1;
8794de0730Smatt
8894de0730Smatt return 0;
8994de0730Smatt }
9094de0730Smatt
9194de0730Smatt static void
digctl_attach(device_t parent,device_t self,void * aux)9294de0730Smatt digctl_attach(device_t parent, device_t self, void *aux)
9394de0730Smatt {
9494de0730Smatt struct digctl_softc *sc = device_private(self);
9594de0730Smatt struct apb_attach_args *aa = aux;
9694de0730Smatt static int digctl_attached = 0;
9794de0730Smatt
9894de0730Smatt sc->sc_dev = self;
9994de0730Smatt sc->sc_iot = aa->aa_iot;
10094de0730Smatt
10194de0730Smatt if (digctl_attached) {
10294de0730Smatt aprint_error_dev(sc->sc_dev, "already attached\n");
10394de0730Smatt return;
10494de0730Smatt }
10594de0730Smatt
10694de0730Smatt if (bus_space_map(sc->sc_iot, aa->aa_addr, aa->aa_size, 0,
10794de0730Smatt &sc->sc_hdl))
10894de0730Smatt {
10994de0730Smatt aprint_error_dev(sc->sc_dev, "Unable to map bus space\n");
11094de0730Smatt return;
11194de0730Smatt }
11294de0730Smatt
11394de0730Smatt digctl_reset(sc);
11494de0730Smatt digctl_init(sc);
11594de0730Smatt
11694de0730Smatt aprint_normal("\n");
11794de0730Smatt
11894de0730Smatt /*
11994de0730Smatt * Setup timecounter to use digctl microseconds counter.
12094de0730Smatt */
12194de0730Smatt tc_useconds.tc_get_timecount = digctl_tc_get_timecount;
12294de0730Smatt tc_useconds.tc_poll_pps = NULL;
12394de0730Smatt tc_useconds.tc_counter_mask = 0xffffffff; /* 32bit counter. */
12494de0730Smatt tc_useconds.tc_frequency = 1000000; /* @ 1MHz */
12594de0730Smatt tc_useconds.tc_name = "digctl";
12694de0730Smatt tc_useconds.tc_quality = 100;
12794de0730Smatt
12894de0730Smatt /* Enable counter. */
12994de0730Smatt DCTL_WR(sc, HW_DIGCTL_CTRL_CLR, HW_DIGCTL_CTRL_XTAL24M_GATE);
13094de0730Smatt
13194de0730Smatt tc_init(&tc_useconds);
13294de0730Smatt
13394de0730Smatt digctl_attached = 1;
13494de0730Smatt
13594de0730Smatt return;
13694de0730Smatt }
13794de0730Smatt
13894de0730Smatt static int
digctl_activate(device_t self,enum devact act)13994de0730Smatt digctl_activate(device_t self, enum devact act)
14094de0730Smatt {
14194de0730Smatt
14294de0730Smatt return EOPNOTSUPP;
14394de0730Smatt }
14494de0730Smatt
14594de0730Smatt /*
14694de0730Smatt * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
14794de0730Smatt */
14894de0730Smatt static void
digctl_reset(struct digctl_softc * sc)14994de0730Smatt digctl_reset(struct digctl_softc *sc)
15094de0730Smatt {
15194de0730Smatt return;
15294de0730Smatt }
15394de0730Smatt
15494de0730Smatt static void
digctl_init(struct digctl_softc * sc)15594de0730Smatt digctl_init(struct digctl_softc *sc)
15694de0730Smatt {
15794de0730Smatt _sc = sc;
15894de0730Smatt return;
15994de0730Smatt }
16094de0730Smatt
16194de0730Smatt /*
16294de0730Smatt * Control USB controller clocks.
16394de0730Smatt */
16494de0730Smatt void
digctl_usb_clkgate(int value)16594de0730Smatt digctl_usb_clkgate(int value)
16694de0730Smatt {
16794de0730Smatt struct digctl_softc *sc = _sc;
16894de0730Smatt
16994de0730Smatt if (sc == NULL) {
170*c56890eeSmsaitoh aprint_error("digctl is not initialized");
17194de0730Smatt return;
17294de0730Smatt }
17394de0730Smatt
17494de0730Smatt if (value) {
17594de0730Smatt /* Clocks OFF. */
17694de0730Smatt DCTL_WR(sc, HW_DIGCTL_CTRL_SET, HW_DIGCTL_CTRL_USB_CLKGATE);
17794de0730Smatt } else {
17894de0730Smatt /* Clocks ON. */
17994de0730Smatt DCTL_WR(sc, HW_DIGCTL_CTRL_CLR, HW_DIGCTL_CTRL_USB_CLKGATE);
18094de0730Smatt }
18194de0730Smatt
18294de0730Smatt return;
18394de0730Smatt }
18494de0730Smatt
18594de0730Smatt /*
18694de0730Smatt *
18794de0730Smatt */
18894de0730Smatt static u_int
digctl_tc_get_timecount(struct timecounter * tc)18994de0730Smatt digctl_tc_get_timecount(struct timecounter *tc)
19094de0730Smatt {
19194de0730Smatt struct digctl_softc *sc = _sc;
19294de0730Smatt return DCTL_RD(sc, HW_DIGCTL_MICROSECONDS);
19394de0730Smatt }
194