]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/usb/chipidea/ulpi.c
Merge tag 'fbdev-v4.11' of git://github.com/bzolnier/linux
[mirror_ubuntu-artful-kernel.git] / drivers / usb / chipidea / ulpi.c
CommitLineData
7bb7e9b1
SB
1/*
2 * Copyright (c) 2016 Linaro Ltd.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/device.h>
15#include <linux/usb/chipidea.h>
16#include <linux/ulpi/interface.h>
17
18#include "ci.h"
19
20#define ULPI_WAKEUP BIT(31)
21#define ULPI_RUN BIT(30)
22#define ULPI_WRITE BIT(29)
23#define ULPI_SYNC_STATE BIT(27)
24#define ULPI_ADDR(n) ((n) << 16)
25#define ULPI_DATA(n) (n)
26
27static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask)
28{
29 unsigned long usec = 10000;
30
31 while (usec--) {
32 if (!hw_read(ci, OP_ULPI_VIEWPORT, mask))
33 return 0;
34
35 udelay(1);
36 }
37
38 return -ETIMEDOUT;
39}
40
41static int ci_ulpi_read(struct device *dev, u8 addr)
42{
43 struct ci_hdrc *ci = dev_get_drvdata(dev);
44 int ret;
45
46 hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
47 ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
48 if (ret)
49 return ret;
50
51 hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr));
52 ret = ci_ulpi_wait(ci, ULPI_RUN);
53 if (ret)
54 return ret;
55
56 return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8;
57}
58
59static int ci_ulpi_write(struct device *dev, u8 addr, u8 val)
60{
61 struct ci_hdrc *ci = dev_get_drvdata(dev);
62 int ret;
63
64 hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
65 ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
66 if (ret)
67 return ret;
68
69 hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff,
70 ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val);
71 return ci_ulpi_wait(ci, ULPI_RUN);
72}
73
74int ci_ulpi_init(struct ci_hdrc *ci)
75{
76 if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
77 return 0;
78
79 /*
80 * Set PORTSC correctly so we can read/write ULPI registers for
81 * identification purposes
82 */
83 hw_phymode_configure(ci);
84
85 ci->ulpi_ops.read = ci_ulpi_read;
86 ci->ulpi_ops.write = ci_ulpi_write;
87 ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops);
88 if (IS_ERR(ci->ulpi))
89 dev_err(ci->dev, "failed to register ULPI interface");
90
91 return PTR_ERR_OR_ZERO(ci->ulpi);
92}
93
94void ci_ulpi_exit(struct ci_hdrc *ci)
95{
96 if (ci->ulpi) {
97 ulpi_unregister_interface(ci->ulpi);
98 ci->ulpi = NULL;
99 }
100}
101
102int ci_ulpi_resume(struct ci_hdrc *ci)
103{
104 int cnt = 100000;
105
106 while (cnt-- > 0) {
107 if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE))
108 return 0;
109 udelay(1);
110 }
111
112 return -ETIMEDOUT;
113}