Merge tag 'usb-for-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes: usb: patches for v3.20 merge window Here's the big pull request for Gadgets and PHYs. It's a total of 217 non-merge commits with pretty much everything being touched. The most important bits are a ton of new documentation for almost all usb gadget functions, a new isp1760 UDC driver, several improvements to the old net2280 UDC driver, and some minor tracepoint improvements to dwc3. Other than that, a big list of minor cleanups, smaller bugfixes and new features all over the place. Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
@@ -107,19 +107,6 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
|
||||
#define fsl_writel(val, addr) writel(val, addr)
|
||||
#endif /* CONFIG_PPC32 */
|
||||
|
||||
/* Routines to access transceiver ULPI registers */
|
||||
u8 view_ulpi(u8 addr)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = 0x40000000 | (addr << 16);
|
||||
fsl_writel(temp, &usb_dr_regs->ulpiview);
|
||||
udelay(1000);
|
||||
while (temp & 0x40)
|
||||
temp = fsl_readl(&usb_dr_regs->ulpiview);
|
||||
return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
|
||||
}
|
||||
|
||||
int write_ulpi(u8 addr, u8 data)
|
||||
{
|
||||
u32 temp;
|
||||
@@ -460,28 +447,6 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
|
||||
fsl_otg_del_timer(fsm, timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce timer count by 1, and find timeout conditions.
|
||||
* Called by fsl_otg 1ms timer interrupt
|
||||
*/
|
||||
int fsl_otg_tick_timer(void)
|
||||
{
|
||||
struct fsl_otg_timer *tmp_timer, *del_tmp;
|
||||
int expired = 0;
|
||||
|
||||
list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
|
||||
tmp_timer->count--;
|
||||
/* check if timer expires */
|
||||
if (!tmp_timer->count) {
|
||||
list_del(&tmp_timer->list);
|
||||
tmp_timer->function(tmp_timer->data);
|
||||
expired = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return expired;
|
||||
}
|
||||
|
||||
/* Reset controller, not reset the bus */
|
||||
void otg_reset_controller(void)
|
||||
{
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/usb_phy_generic.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -39,6 +40,10 @@
|
||||
|
||||
#include "phy-generic.h"
|
||||
|
||||
#define VBUS_IRQ_FLAGS \
|
||||
(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
|
||||
IRQF_ONESHOT)
|
||||
|
||||
struct platform_device *usb_phy_generic_register(void)
|
||||
{
|
||||
return platform_device_register_simple("usb_phy_generic",
|
||||
@@ -59,19 +64,79 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
|
||||
|
||||
static void nop_reset_set(struct usb_phy_generic *nop, int asserted)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (!gpio_is_valid(nop->gpio_reset))
|
||||
if (!nop->gpiod_reset)
|
||||
return;
|
||||
|
||||
value = asserted;
|
||||
if (nop->reset_active_low)
|
||||
value = !value;
|
||||
gpiod_direction_output(nop->gpiod_reset, !asserted);
|
||||
usleep_range(10000, 20000);
|
||||
gpiod_set_value(nop->gpiod_reset, asserted);
|
||||
}
|
||||
|
||||
gpio_set_value_cansleep(nop->gpio_reset, value);
|
||||
/* interface to regulator framework */
|
||||
static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
|
||||
{
|
||||
struct regulator *vbus_draw = nop->vbus_draw;
|
||||
int enabled;
|
||||
int ret;
|
||||
|
||||
if (!asserted)
|
||||
usleep_range(10000, 20000);
|
||||
if (!vbus_draw)
|
||||
return;
|
||||
|
||||
enabled = nop->vbus_draw_enabled;
|
||||
if (mA) {
|
||||
regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
|
||||
if (!enabled) {
|
||||
ret = regulator_enable(vbus_draw);
|
||||
if (ret < 0)
|
||||
return;
|
||||
nop->vbus_draw_enabled = 1;
|
||||
}
|
||||
} else {
|
||||
if (enabled) {
|
||||
ret = regulator_disable(vbus_draw);
|
||||
if (ret < 0)
|
||||
return;
|
||||
nop->vbus_draw_enabled = 0;
|
||||
}
|
||||
}
|
||||
nop->mA = mA;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
|
||||
{
|
||||
struct usb_phy_generic *nop = data;
|
||||
struct usb_otg *otg = nop->phy.otg;
|
||||
int vbus, status;
|
||||
|
||||
vbus = gpiod_get_value(nop->gpiod_vbus);
|
||||
if ((vbus ^ nop->vbus) == 0)
|
||||
return IRQ_HANDLED;
|
||||
nop->vbus = vbus;
|
||||
|
||||
if (vbus) {
|
||||
status = USB_EVENT_VBUS;
|
||||
otg->state = OTG_STATE_B_PERIPHERAL;
|
||||
nop->phy.last_event = status;
|
||||
usb_gadget_vbus_connect(otg->gadget);
|
||||
|
||||
/* drawing a "unit load" is *always* OK, except for OTG */
|
||||
nop_set_vbus_draw(nop, 100);
|
||||
|
||||
atomic_notifier_call_chain(&nop->phy.notifier, status,
|
||||
otg->gadget);
|
||||
} else {
|
||||
nop_set_vbus_draw(nop, 0);
|
||||
|
||||
usb_gadget_vbus_disconnect(otg->gadget);
|
||||
status = USB_EVENT_NONE;
|
||||
otg->state = OTG_STATE_B_IDLE;
|
||||
nop->phy.last_event = status;
|
||||
|
||||
atomic_notifier_call_chain(&nop->phy.notifier, status,
|
||||
otg->gadget);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int usb_gen_phy_init(struct usb_phy *phy)
|
||||
@@ -143,37 +208,48 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
|
||||
struct usb_phy_generic_platform_data *pdata)
|
||||
{
|
||||
enum usb_phy_type type = USB_PHY_TYPE_USB2;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
u32 clk_rate = 0;
|
||||
bool needs_vcc = false;
|
||||
|
||||
nop->reset_active_low = true; /* default behaviour */
|
||||
|
||||
if (dev->of_node) {
|
||||
struct device_node *node = dev->of_node;
|
||||
enum of_gpio_flags flags = 0;
|
||||
|
||||
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
|
||||
clk_rate = 0;
|
||||
|
||||
needs_vcc = of_property_read_bool(node, "vcc-supply");
|
||||
nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
|
||||
0, &flags);
|
||||
if (nop->gpio_reset == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
|
||||
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
|
||||
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
|
||||
if (!err) {
|
||||
nop->gpiod_vbus = devm_gpiod_get_optional(dev,
|
||||
"vbus-detect");
|
||||
err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
|
||||
}
|
||||
} else if (pdata) {
|
||||
type = pdata->type;
|
||||
clk_rate = pdata->clk_rate;
|
||||
needs_vcc = pdata->needs_vcc;
|
||||
nop->gpio_reset = pdata->gpio_reset;
|
||||
} else {
|
||||
nop->gpio_reset = -1;
|
||||
if (gpio_is_valid(pdata->gpio_reset)) {
|
||||
err = devm_gpio_request_one(dev, pdata->gpio_reset, 0,
|
||||
dev_name(dev));
|
||||
if (!err)
|
||||
nop->gpiod_reset =
|
||||
gpio_to_desc(pdata->gpio_reset);
|
||||
}
|
||||
nop->gpiod_vbus = pdata->gpiod_vbus;
|
||||
}
|
||||
|
||||
if (err == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (err) {
|
||||
dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
|
||||
return err;
|
||||
}
|
||||
if (nop->gpiod_reset)
|
||||
gpiod_direction_output(nop->gpiod_reset, 1);
|
||||
|
||||
nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
|
||||
GFP_KERNEL);
|
||||
if (!nop->phy.otg)
|
||||
@@ -201,24 +277,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(nop->gpio_reset)) {
|
||||
unsigned long gpio_flags;
|
||||
|
||||
/* Assert RESET */
|
||||
if (nop->reset_active_low)
|
||||
gpio_flags = GPIOF_OUT_INIT_LOW;
|
||||
else
|
||||
gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
|
||||
err = devm_gpio_request_one(dev, nop->gpio_reset,
|
||||
gpio_flags, dev_name(dev));
|
||||
if (err) {
|
||||
dev_err(dev, "Error requesting RESET GPIO %d\n",
|
||||
nop->gpio_reset);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
nop->dev = dev;
|
||||
nop->phy.dev = nop->dev;
|
||||
nop->phy.label = "nop-xceiv";
|
||||
@@ -247,6 +305,18 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
|
||||
err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
|
||||
if (err)
|
||||
return err;
|
||||
if (nop->gpiod_vbus) {
|
||||
err = devm_request_threaded_irq(&pdev->dev,
|
||||
gpiod_to_irq(nop->gpiod_vbus),
|
||||
NULL, nop_gpio_vbus_thread,
|
||||
VBUS_IRQ_FLAGS, "vbus_detect",
|
||||
nop);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
|
||||
gpiod_to_irq(nop->gpiod_vbus), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
nop->phy.init = usb_gen_phy_init;
|
||||
nop->phy.shutdown = usb_gen_phy_shutdown;
|
||||
|
@@ -2,14 +2,20 @@
|
||||
#define _PHY_GENERIC_H_
|
||||
|
||||
#include <linux/usb/usb_phy_generic.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
struct usb_phy_generic {
|
||||
struct usb_phy phy;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
struct regulator *vcc;
|
||||
int gpio_reset;
|
||||
bool reset_active_low;
|
||||
struct gpio_desc *gpiod_reset;
|
||||
struct gpio_desc *gpiod_vbus;
|
||||
struct regulator *vbus_draw;
|
||||
bool vbus_draw_enabled;
|
||||
unsigned long mA;
|
||||
unsigned int vbus;
|
||||
};
|
||||
|
||||
int usb_gen_phy_init(struct usb_phy *phy);
|
||||
|
@@ -40,6 +40,7 @@
|
||||
|
||||
#define BM_USBPHY_CTRL_SFTRST BIT(31)
|
||||
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
|
||||
#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
|
||||
#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
|
||||
#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
|
||||
#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
|
||||
@@ -69,6 +70,9 @@
|
||||
#define ANADIG_USB2_LOOPBACK_SET 0x244
|
||||
#define ANADIG_USB2_LOOPBACK_CLR 0x248
|
||||
|
||||
#define ANADIG_USB1_MISC 0x1f0
|
||||
#define ANADIG_USB2_MISC 0x250
|
||||
|
||||
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
|
||||
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
|
||||
|
||||
@@ -80,6 +84,11 @@
|
||||
#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
|
||||
#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
|
||||
|
||||
#define BM_ANADIG_USB1_MISC_RX_VPIN_FS BIT(29)
|
||||
#define BM_ANADIG_USB1_MISC_RX_VMIN_FS BIT(28)
|
||||
#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
|
||||
#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
|
||||
|
||||
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
|
||||
|
||||
/* Do disconnection between PHY and controller without vbus */
|
||||
@@ -131,8 +140,7 @@ static const struct mxs_phy_data vf610_phy_data = {
|
||||
};
|
||||
|
||||
static const struct mxs_phy_data imx6sx_phy_data = {
|
||||
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
|
||||
MXS_PHY_NEED_IP_FIX,
|
||||
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
|
||||
};
|
||||
|
||||
static const struct of_device_id mxs_phy_dt_ids[] = {
|
||||
@@ -256,6 +264,18 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
|
||||
static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
|
||||
{
|
||||
void __iomem *base = mxs_phy->phy.io_priv;
|
||||
u32 phyctrl = readl(base + HW_USBPHY_CTRL);
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_OTG) &&
|
||||
!(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
|
||||
{
|
||||
bool vbus_is_on = false;
|
||||
@@ -270,7 +290,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
|
||||
|
||||
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
|
||||
|
||||
if (on && !vbus_is_on)
|
||||
if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
|
||||
__mxs_phy_disconnect_line(mxs_phy, true);
|
||||
else
|
||||
__mxs_phy_disconnect_line(mxs_phy, false);
|
||||
@@ -293,6 +313,17 @@ static int mxs_phy_init(struct usb_phy *phy)
|
||||
static void mxs_phy_shutdown(struct usb_phy *phy)
|
||||
{
|
||||
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
|
||||
u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
|
||||
BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
|
||||
BM_USBPHY_CTRL_ENIDCHG_WKUP |
|
||||
BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
|
||||
BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
|
||||
BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
|
||||
BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
|
||||
BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
|
||||
|
||||
writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
|
||||
writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
|
||||
|
||||
writel(BM_USBPHY_CTRL_CLKGATE,
|
||||
phy->io_priv + HW_USBPHY_CTRL_SET);
|
||||
@@ -300,13 +331,56 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
|
||||
clk_disable_unprepare(mxs_phy->clk);
|
||||
}
|
||||
|
||||
static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
|
||||
{
|
||||
unsigned int line_state;
|
||||
/* bit definition is the same for all controllers */
|
||||
unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
|
||||
dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
|
||||
unsigned int reg = ANADIG_USB1_MISC;
|
||||
|
||||
/* If the SoCs don't have anatop, quit */
|
||||
if (!mxs_phy->regmap_anatop)
|
||||
return false;
|
||||
|
||||
if (mxs_phy->port_id == 0)
|
||||
reg = ANADIG_USB1_MISC;
|
||||
else if (mxs_phy->port_id == 1)
|
||||
reg = ANADIG_USB2_MISC;
|
||||
|
||||
regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
|
||||
|
||||
if ((line_state & (dp_bit | dm_bit)) == dm_bit)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mxs_phy_suspend(struct usb_phy *x, int suspend)
|
||||
{
|
||||
int ret;
|
||||
struct mxs_phy *mxs_phy = to_mxs_phy(x);
|
||||
bool low_speed_connection, vbus_is_on;
|
||||
|
||||
low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
|
||||
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
|
||||
|
||||
if (suspend) {
|
||||
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
|
||||
/*
|
||||
* FIXME: Do not power down RXPWD1PT1 bit for low speed
|
||||
* connect. The low speed connection will have problem at
|
||||
* very rare cases during usb suspend and resume process.
|
||||
*/
|
||||
if (low_speed_connection & vbus_is_on) {
|
||||
/*
|
||||
* If value to be set as pwd value is not 0xffffffff,
|
||||
* several 32Khz cycles are needed.
|
||||
*/
|
||||
mxs_phy_clock_switch_delay();
|
||||
writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
|
||||
} else {
|
||||
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
|
||||
}
|
||||
writel(BM_USBPHY_CTRL_CLKGATE,
|
||||
x->io_priv + HW_USBPHY_CTRL_SET);
|
||||
clk_disable_unprepare(mxs_phy->clk);
|
||||
@@ -359,7 +433,9 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
|
||||
dev_dbg(phy->dev, "%s device has disconnected\n",
|
||||
(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
|
||||
|
||||
if (speed == USB_SPEED_HIGH)
|
||||
/* Sometimes, the speed is not high speed when the error occurs */
|
||||
if (readl(phy->io_priv + HW_USBPHY_CTRL) &
|
||||
BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
|
||||
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
|
||||
phy->io_priv + HW_USBPHY_CTRL_CLR);
|
||||
|
||||
|
مرجع در شماره جدید
Block a user