usb-da8xx.c 7.9 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4
/*
 * DA8xx USB
 */
5 6
#include <linux/clk.h>
#include <linux/delay.h>
7 8
#include <linux/dma-mapping.h>
#include <linux/init.h>
9
#include <linux/mfd/da8xx-cfgchip.h>
10
#include <linux/phy/phy.h>
11 12 13 14
#include <linux/platform_data/usb-davinci.h>
#include <linux/platform_device.h>
#include <linux/usb/musb.h>

15
#include <mach/clock.h>
16 17 18 19 20
#include <mach/common.h>
#include <mach/cputype.h>
#include <mach/da8xx.h>
#include <mach/irqs.h>

21 22
#include "clock.h"

23 24 25
#define DA8XX_USB0_BASE		0x01e00000
#define DA8XX_USB1_BASE		0x01e25000

26 27
static struct clk *usb20_clk;

28 29 30
static struct platform_device da8xx_usb_phy = {
	.name		= "da8xx-usb-phy",
	.id		= -1,
31 32 33 34 35 36 37 38
	.dev		= {
		/*
		 * Setting init_name so that clock lookup will work in
		 * da8xx_register_usb11_phy_clk() even if this device is not
		 * registered yet.
		 */
		.init_name	= "da8xx-usb-phy",
	},
39 40 41 42 43 44 45
};

int __init da8xx_register_usb_phy(void)
{
	return platform_device_register(&da8xx_usb_phy);
}

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static struct musb_hdrc_config musb_config = {
	.multipoint	= true,
	.num_eps	= 5,
	.ram_bits	= 10,
};

static struct musb_hdrc_platform_data usb_data = {
	/* OTG requires a Mini-AB connector */
	.mode           = MUSB_OTG,
	.clock		= "usb20",
	.config		= &musb_config,
};

static struct resource da8xx_usb20_resources[] = {
	{
		.start		= DA8XX_USB0_BASE,
		.end		= DA8XX_USB0_BASE + SZ_64K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= IRQ_DA8XX_USB_INT,
		.flags		= IORESOURCE_IRQ,
		.name		= "mc",
	},
};

static u64 usb_dmamask = DMA_BIT_MASK(32);

74
static struct platform_device da8xx_usb20_dev = {
75 76 77
	.name		= "musb-da8xx",
	.id             = -1,
	.dev = {
78 79 80 81 82
		/*
		 * Setting init_name so that clock lookup will work in
		 * usb20_phy_clk_enable() even if this device is not registered.
		 */
		.init_name		= "musb-da8xx",
83 84 85 86 87 88 89 90 91 92 93 94 95
		.platform_data		= &usb_data,
		.dma_mask		= &usb_dmamask,
		.coherent_dma_mask      = DMA_BIT_MASK(32),
	},
	.resource	= da8xx_usb20_resources,
	.num_resources	= ARRAY_SIZE(da8xx_usb20_resources),
};

int __init da8xx_register_usb20(unsigned int mA, unsigned int potpgt)
{
	usb_data.power	= mA > 510 ? 255 : mA / 2;
	usb_data.potpgt = (potpgt + 1) / 2;

96
	return platform_device_register(&da8xx_usb20_dev);
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
}

static struct resource da8xx_usb11_resources[] = {
	[0] = {
		.start	= DA8XX_USB1_BASE,
		.end	= DA8XX_USB1_BASE + SZ_4K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_DA8XX_IRQN,
		.end	= IRQ_DA8XX_IRQN,
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 da8xx_usb11_dma_mask = DMA_BIT_MASK(32);

static struct platform_device da8xx_usb11_device = {
115 116
	.name		= "ohci-da8xx",
	.id		= -1,
117 118 119 120 121 122 123 124 125 126 127 128 129
	.dev = {
		.dma_mask		= &da8xx_usb11_dma_mask,
		.coherent_dma_mask	= DMA_BIT_MASK(32),
	},
	.num_resources	= ARRAY_SIZE(da8xx_usb11_resources),
	.resource	= da8xx_usb11_resources,
};

int __init da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata)
{
	da8xx_usb11_device.dev.platform_data = pdata;
	return platform_device_register(&da8xx_usb11_device);
}
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

static struct clk usb_refclkin = {
	.name		= "usb_refclkin",
	.set_rate	= davinci_simple_set_rate,
};

static struct clk_lookup usb_refclkin_lookup =
	CLK(NULL, "usb_refclkin", &usb_refclkin);

/**
 * da8xx_register_usb_refclkin - register USB_REFCLKIN clock
 *
 * @rate: The clock rate in Hz
 *
 * This clock is only needed if the board provides an external USB_REFCLKIN
 * signal, in which case it will be used as the parent of usb20_phy_clk and/or
 * usb11_phy_clk.
 */
int __init da8xx_register_usb_refclkin(int rate)
{
	int ret;

	usb_refclkin.rate = rate;
	ret = clk_register(&usb_refclkin);
	if (ret)
		return ret;

	clkdev_add(&usb_refclkin_lookup);

	return 0;
}

static void usb20_phy_clk_enable(struct clk *clk)
{
	u32 val;
	u32 timeout = 500000; /* 500 msec */

	val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	/* The USB 2.O PLL requires that the USB 2.O PSC is enabled as well. */
170
	davinci_clk_enable(usb20_clk);
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

	/*
	 * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
	 * host may use the PLL clock without USB 2.0 OTG being used.
	 */
	val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
	val |= CFGCHIP2_PHY_PLLON;

	writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	while (--timeout) {
		val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
		if (val & CFGCHIP2_PHYCLKGD)
			goto done;
		udelay(1);
	}

	pr_err("Timeout waiting for USB 2.0 PHY clock good\n");
done:
190
	davinci_clk_disable(usb20_clk);
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
}

static void usb20_phy_clk_disable(struct clk *clk)
{
	u32 val;

	val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
	val |= CFGCHIP2_PHYPWRDN;
	writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
}

static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent)
{
	u32 val;

	val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	/* Set the mux depending on the parent clock. */
	if (parent == &usb_refclkin) {
		val &= ~CFGCHIP2_USB2PHYCLKMUX;
	} else if (strcmp(parent->name, "pll0_aux_clk") == 0) {
		val |= CFGCHIP2_USB2PHYCLKMUX;
	} else {
		pr_err("Bad parent on USB 2.0 PHY clock\n");
		return -EINVAL;
	}

	/* reference frequency also comes from parent clock */
	val &= ~CFGCHIP2_REFFREQ_MASK;
	switch (clk_get_rate(parent)) {
	case 12000000:
		val |= CFGCHIP2_REFFREQ_12MHZ;
		break;
	case 13000000:
		val |= CFGCHIP2_REFFREQ_13MHZ;
		break;
	case 19200000:
		val |= CFGCHIP2_REFFREQ_19_2MHZ;
		break;
	case 20000000:
		val |= CFGCHIP2_REFFREQ_20MHZ;
		break;
	case 24000000:
		val |= CFGCHIP2_REFFREQ_24MHZ;
		break;
	case 26000000:
		val |= CFGCHIP2_REFFREQ_26MHZ;
		break;
	case 38400000:
		val |= CFGCHIP2_REFFREQ_38_4MHZ;
		break;
	case 40000000:
		val |= CFGCHIP2_REFFREQ_40MHZ;
		break;
	case 48000000:
		val |= CFGCHIP2_REFFREQ_48MHZ;
		break;
	default:
		pr_err("Bad parent clock rate on USB 2.0 PHY clock\n");
		return -EINVAL;
	}

	writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	return 0;
}

static struct clk usb20_phy_clk = {
	.name		= "usb20_phy",
	.clk_enable	= usb20_phy_clk_enable,
	.clk_disable	= usb20_phy_clk_disable,
	.set_parent	= usb20_phy_clk_set_parent,
};

static struct clk_lookup usb20_phy_clk_lookup =
	CLK("da8xx-usb-phy", "usb20_phy", &usb20_phy_clk);

/**
 * da8xx_register_usb20_phy_clk - register USB0PHYCLKMUX clock
 *
 * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
 *	or "pll0_aux" if false.
 */
int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
{
	struct clk *parent;
277 278 279 280 281 282
	int ret;

	usb20_clk = clk_get(&da8xx_usb20_dev.dev, "usb20");
	ret = PTR_ERR_OR_ZERO(usb20_clk);
	if (ret)
		return ret;
283 284

	parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux");
285 286 287 288 289
	ret = PTR_ERR_OR_ZERO(parent);
	if (ret) {
		clk_put(usb20_clk);
		return ret;
	}
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356

	usb20_phy_clk.parent = parent;
	ret = clk_register(&usb20_phy_clk);
	if (!ret)
		clkdev_add(&usb20_phy_clk_lookup);

	clk_put(parent);

	return ret;
}

static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent)
{
	u32 val;

	val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	/* Set the USB 1.1 PHY clock mux based on the parent clock. */
	if (parent == &usb20_phy_clk) {
		val &= ~CFGCHIP2_USB1PHYCLKMUX;
	} else if (parent == &usb_refclkin) {
		val |= CFGCHIP2_USB1PHYCLKMUX;
	} else {
		pr_err("Bad parent on USB 1.1 PHY clock\n");
		return -EINVAL;
	}

	writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	return 0;
}

static struct clk usb11_phy_clk = {
	.name		= "usb11_phy",
	.set_parent	= usb11_phy_clk_set_parent,
};

static struct clk_lookup usb11_phy_clk_lookup =
	CLK("da8xx-usb-phy", "usb11_phy", &usb11_phy_clk);

/**
 * da8xx_register_usb11_phy_clk - register USB1PHYCLKMUX clock
 *
 * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
 *	or "usb20_phy" if false.
 */
int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin)
{
	struct clk *parent;
	int ret = 0;

	if (use_usb_refclkin)
		parent = clk_get(NULL, "usb_refclkin");
	else
		parent = clk_get(&da8xx_usb_phy.dev, "usb20_phy");
	if (IS_ERR(parent))
		return PTR_ERR(parent);

	usb11_phy_clk.parent = parent;
	ret = clk_register(&usb11_phy_clk);
	if (!ret)
		clkdev_add(&usb11_phy_clk_lookup);

	clk_put(parent);

	return ret;
}