aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/isp1760/isp1760-if.c
blob: c96ab459f93e66cc2d52930cff52f17163863d39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
 *
 * based on original code from:
 * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
 */

#include <common.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <dm/lists.h>
#include <linux/bug.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/usb/otg.h>
#include <log.h>
#include <usb.h>

#include "isp1760-core.h"
#include "isp1760-regs.h"
#include "isp1760-uboot.h"

static int isp1760_of_to_plat(struct udevice *dev)
{
	struct isp1760_device *isp = dev_get_plat(dev);
	unsigned int devflags = 0;
	u32 bus_width = 0;
	ofnode dp;

	if (!dev_has_ofnode(dev)) {
		/* select isp1763 as the default device */
		devflags = ISP1760_FLAG_ISP1763 | ISP1760_FLAG_BUS_WIDTH_16;
		pr_err("isp1760: no platform data\n");
		goto isp_setup;
	}

	dp = dev_ofnode(dev);

	if (ofnode_device_is_compatible(dp, "nxp,usb-isp1761"))
		devflags |= ISP1760_FLAG_ISP1761;

	if (ofnode_device_is_compatible(dp, "nxp,usb-isp1763"))
		devflags |= ISP1760_FLAG_ISP1763;

	/*
	 * Some systems wire up only 8 of 16 data lines or
	 * 16 of the 32 data lines
	 */
	bus_width = ofnode_read_u32_default(dp, "bus-width", 16);
	if (bus_width == 16)
		devflags |= ISP1760_FLAG_BUS_WIDTH_16;
	else if (bus_width == 8)
		devflags |= ISP1760_FLAG_BUS_WIDTH_8;

	if (usb_get_dr_mode(dev_ofnode(dev)) == USB_DR_MODE_PERIPHERAL)
		devflags |= ISP1760_FLAG_PERIPHERAL_EN;

	if (ofnode_read_bool(dp, "analog-oc"))
		devflags |= ISP1760_FLAG_ANALOG_OC;

	if (ofnode_read_bool(dp, "dack-polarity"))
		devflags |= ISP1760_FLAG_DACK_POL_HIGH;

	if (ofnode_read_bool(dp, "dreq-polarity"))
		devflags |= ISP1760_FLAG_DREQ_POL_HIGH;

isp_setup:
	isp->devflags = devflags;
	isp->dev = dev;

	return 0;
}

static int isp1760_plat_probe(struct udevice *dev)
{
	struct isp1760_device *isp = dev_get_plat(dev);
	struct resource mem_res;
	struct resource irq_res;
	int ret;

	dev_read_resource(dev, 0, &mem_res);
	dev_read_resource(dev, 1, &irq_res);

	isp1760_init_kmem_once();

	ret = isp1760_register(isp, &mem_res, irq_res.start, irq_res.flags);
	if (ret < 0) {
		isp1760_deinit_kmem_cache();
		return ret;
	}

	return 0;
}

static int isp1760_plat_remove(struct udevice *dev)
{
	struct isp1760_device *isp = dev_get_plat(dev);

	isp1760_deinit_kmem_cache();
	isp1760_unregister(isp);

	return 0;
}

static const struct udevice_id isp1760_ids[] = {
	{ .compatible = "nxp,usb-isp1760", },
	{ .compatible = "nxp,usb-isp1761", },
	{ .compatible = "nxp,usb-isp1763", },
	{ },
};

U_BOOT_DRIVER(isp1760) = {
	.name		= "isp1760",
	.id		= UCLASS_USB,
	.of_match	= isp1760_ids,
	.of_to_plat	= isp1760_of_to_plat,
	.ops		= &isp1760_usb_ops,
	.probe		= isp1760_plat_probe,
	.remove		= isp1760_plat_remove,
	.plat_auto	= sizeof(struct isp1760_device),
	.priv_auto	= sizeof(struct isp1760_host_data),
};