1132332Smarcel/*-
2132360Smarcel * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
3132332Smarcel * All rights reserved.
4132332Smarcel *
5132332Smarcel * Redistribution and use in source and binary forms, with or without
6132332Smarcel * modification, are permitted provided that the following conditions
7132332Smarcel * are met:
8132332Smarcel * 1. Redistributions of source code must retain the above copyright
9132332Smarcel *    notice, this list of conditions and the following disclaimer.
10132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11132332Smarcel *    notice, this list of conditions and the following disclaimer in the
12132332Smarcel *    documentation and/or other materials provided with the distribution.
13132332Smarcel *
14132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132332Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132332Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132332Smarcel * SUCH DAMAGE.
25132332Smarcel */
26132332Smarcel
27132332Smarcel#include <sys/cdefs.h>
28132332Smarcel__FBSDID("$FreeBSD: releng/10.3/sys/arm/freescale/imx/imx6_usbphy.c 266371 2014-05-17 22:29:24Z ian $");
29132332Smarcel
30132332Smarcel/*
31132332Smarcel * USBPHY driver for Freescale i.MX6 family of SoCs.
32132332Smarcel */
33132332Smarcel
34132332Smarcel#include "opt_bus.h"
35132332Smarcel
36132332Smarcel#include <sys/param.h>
37132332Smarcel#include <sys/systm.h>
38132332Smarcel#include <sys/kernel.h>
39132332Smarcel#include <sys/module.h>
40132332Smarcel#include <sys/bus.h>
41132332Smarcel#include <sys/rman.h>
42132332Smarcel
43132332Smarcel#include <dev/ofw/ofw_bus.h>
44132332Smarcel#include <dev/ofw/ofw_bus_subr.h>
45132332Smarcel
46132332Smarcel#include <machine/bus.h>
47132332Smarcel
48132332Smarcel#include <arm/freescale/imx/imx_ccmvar.h>
49132332Smarcel#include <arm/freescale/imx/imx6_anatopreg.h>
50132332Smarcel#include <arm/freescale/imx/imx6_anatopvar.h>
51132332Smarcel
52132332Smarcel/*
53132332Smarcel * Hardware register defines.
54132332Smarcel */
55132332Smarcel#define	PWD_REG				0x0000
56132332Smarcel#define	CTRL_STATUS_REG			0x0030
57132332Smarcel#define	CTRL_SET_REG			0x0034
58132332Smarcel#define	CTRL_CLR_REG			0x0038
59132332Smarcel#define	CTRL_TOGGLE_REG			0x003c
60144922Sdavidxu#define	  CTRL_SFTRST			  (1U << 31)
61132332Smarcel#define	  CTRL_CLKGATE			  (1 << 30)
62132332Smarcel#define	  CTRL_ENUTMILEVEL3		  (1 << 15)
63132332Smarcel#define	  CTRL_ENUTMILEVEL2		  (1 << 14)
64132332Smarcel
65132332Smarcelstruct usbphy_softc {
66132332Smarcel	device_t	dev;
67132332Smarcel	struct resource	*mem_res;
68132332Smarcel	u_int		phy_num;
69132332Smarcel};
70132332Smarcel
71132332Smarcelstatic int
72132332Smarcelusbphy_detach(device_t dev)
73132332Smarcel{
74132332Smarcel	struct usbphy_softc *sc;
75132332Smarcel
76132360Smarcel	sc = device_get_softc(dev);
77132360Smarcel
78132360Smarcel	if (sc->mem_res != NULL)
79132360Smarcel		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
80132360Smarcel
81132360Smarcel	return (0);
82132360Smarcel}
83132360Smarcel
84132360Smarcelstatic int
85132360Smarcelusbphy_attach(device_t dev)
86132360Smarcel{
87132360Smarcel	struct usbphy_softc *sc;
88132360Smarcel	int err, regoff, rid;
89132360Smarcel
90132332Smarcel	sc = device_get_softc(dev);
91132332Smarcel	err = 0;
92132332Smarcel
93132332Smarcel	/* Allocate bus_space resources. */
94132332Smarcel	rid = 0;
95132332Smarcel	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
96132332Smarcel	    RF_ACTIVE);
97132332Smarcel	if (sc->mem_res == NULL) {
98183021Smarcel		device_printf(dev, "Cannot allocate memory resources\n");
99132332Smarcel		err = ENXIO;
100132332Smarcel		goto out;
101132332Smarcel	}
102132332Smarcel
103132332Smarcel	/*
104132360Smarcel	 * XXX Totally lame way to get the unit number (but not quite as lame as
105132360Smarcel	 * adding an ad-hoc property to the fdt data).  This works as long as
106132360Smarcel	 * this driver is used for imx6 only.
107132360Smarcel	 */
108132360Smarcel	const uint32_t PWD_PHY1_REG_PHYSADDR = 0x020c9000;
109132360Smarcel	if (BUS_SPACE_PHYSADDR(sc->mem_res, 0) == PWD_PHY1_REG_PHYSADDR) {
110132332Smarcel		sc->phy_num = 0;
111132360Smarcel		regoff = 0;
112132332Smarcel	} else {
113132332Smarcel		sc->phy_num = 1;
114132360Smarcel		regoff = 0x60;
115132332Smarcel	}
116132332Smarcel
117132332Smarcel	/*
118132332Smarcel	 * Based on a note in the u-boot source code, disable charger detection
119132332Smarcel	 * to avoid degrading the differential signaling on the DP line.  Note
120132332Smarcel	 * that this disables (by design) both charger detection and contact
121132332Smarcel	 * detection, because of the screwball mix of active-high and active-low
122132332Smarcel	 * bits in this register.
123132332Smarcel	 */
124132332Smarcel	imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff,
125132332Smarcel	    IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE |
126132332Smarcel	    IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG);
127132332Smarcel
128132332Smarcel	imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff,
129132332Smarcel	    IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE |
130132332Smarcel	    IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG);
131132332Smarcel
132132332Smarcel	/* XXX Configure the overcurrent detection here. */
133132332Smarcel
134132332Smarcel	/*
135132332Smarcel	 * Turn on the phy clocks.
136132332Smarcel	 */
137132332Smarcel	imx_ccm_usbphy_enable(dev);
138132332Smarcel
139132332Smarcel	/*
140132332Smarcel	 * Set the software reset bit, then clear both it and the clock gate bit
141132332Smarcel	 * to bring the device out of reset with the clock running.
142132332Smarcel	 */
143132332Smarcel	bus_write_4(sc->mem_res, CTRL_SET_REG, CTRL_SFTRST);
144132332Smarcel	bus_write_4(sc->mem_res, CTRL_CLR_REG, CTRL_SFTRST | CTRL_CLKGATE);
145132332Smarcel
146132332Smarcel	/* Power up: clear all bits in the powerdown register. */
147132332Smarcel	bus_write_4(sc->mem_res, PWD_REG, 0);
148132332Smarcel
149132332Smarcel	err = 0;
150132332Smarcel
151132332Smarcelout:
152132332Smarcel
153132332Smarcel	if (err != 0)
154132332Smarcel		usbphy_detach(dev);
155132332Smarcel
156132332Smarcel	return (err);
157132332Smarcel}
158132332Smarcel
159132332Smarcelstatic int
160132332Smarcelusbphy_probe(device_t dev)
161132332Smarcel{
162132332Smarcel
163132332Smarcel	if (!ofw_bus_status_okay(dev))
164132332Smarcel		return (ENXIO);
165132332Smarcel
166132332Smarcel	if (ofw_bus_is_compatible(dev, "fsl,imx6q-usbphy") == 0)
167132332Smarcel		return (ENXIO);
168132332Smarcel
169132332Smarcel	device_set_desc(dev, "Freescale i.MX6 USB PHY");
170132332Smarcel
171132332Smarcel	return (BUS_PROBE_DEFAULT);
172132332Smarcel}
173132332Smarcel
174132332Smarcelstatic device_method_t usbphy_methods[] = {
175132360Smarcel	/* Device interface */
176132332Smarcel	DEVMETHOD(device_probe,  usbphy_probe),
177132332Smarcel	DEVMETHOD(device_attach, usbphy_attach),
178132332Smarcel	DEVMETHOD(device_detach, usbphy_detach),
179132332Smarcel
180144663Sdavidxu	DEVMETHOD_END
181132332Smarcel};
182132332Smarcel
183132332Smarcelstatic driver_t usbphy_driver = {
184132332Smarcel	"usbphy",
185132332Smarcel	usbphy_methods,
186132332Smarcel	sizeof(struct usbphy_softc)
187193826Sdes};
188132332Smarcel
189132332Smarcelstatic devclass_t usbphy_devclass;
190132332Smarcel
191132332SmarcelDRIVER_MODULE(usbphy, simplebus, usbphy_driver, usbphy_devclass, 0, 0);
192132332Smarcel
193132332Smarcel