forked from luck/tmp_suning_uos_patched
usb: phy: ab8500-usb: update irq handling code
Update irq handling code to notify all possible link status changes of AB8500 and AB8505 to the ux500-musb glue driver. The additional event codes will be used for pm-runtime implementation, and are defined in a separate ux500-specific header. This also modify the irq registration code to use devm_* helpers and drop all non necessary fail path code. Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Fabio Baltieri <fabio.baltieri@linaro.org> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
73f226cbd7
commit
af6882be36
|
@ -26,6 +26,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/musb-ux500.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
|
@ -107,15 +108,15 @@ static int musb_otg_notifications(struct notifier_block *nb,
|
|||
event, usb_otg_state_string(musb->xceiv->state));
|
||||
|
||||
switch (event) {
|
||||
case USB_EVENT_ID:
|
||||
case UX500_MUSB_ID:
|
||||
dev_dbg(musb->controller, "ID GND\n");
|
||||
ux500_musb_set_vbus(musb, 1);
|
||||
break;
|
||||
case USB_EVENT_VBUS:
|
||||
case UX500_MUSB_VBUS:
|
||||
dev_dbg(musb->controller, "VBUS Connect\n");
|
||||
ux500_musb_set_vbus(musb, 0);
|
||||
break;
|
||||
case USB_EVENT_NONE:
|
||||
case UX500_MUSB_NONE:
|
||||
dev_dbg(musb->controller, "VBUS Disconnect\n");
|
||||
if (is_host_active(musb))
|
||||
ux500_musb_set_vbus(musb, 0);
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/usb/musb-ux500.h>
|
||||
|
||||
#define AB8500_MAIN_WD_CTRL_REG 0x01
|
||||
#define AB8500_USB_LINE_STAT_REG 0x80
|
||||
#define AB8505_USB_LINE_STAT_REG 0x94
|
||||
#define AB8500_USB_PHY_CTRL_REG 0x8A
|
||||
|
||||
#define AB8500_BIT_OTG_STAT_ID (1 << 0)
|
||||
|
@ -44,36 +46,76 @@
|
|||
|
||||
#define AB8500_WD_KICK_DELAY_US 100 /* usec */
|
||||
#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
|
||||
#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */
|
||||
|
||||
/* Usb line status register */
|
||||
enum ab8500_usb_link_status {
|
||||
USB_LINK_NOT_CONFIGURED = 0,
|
||||
USB_LINK_STD_HOST_NC,
|
||||
USB_LINK_STD_HOST_C_NS,
|
||||
USB_LINK_STD_HOST_C_S,
|
||||
USB_LINK_HOST_CHG_NM,
|
||||
USB_LINK_HOST_CHG_HS,
|
||||
USB_LINK_HOST_CHG_HS_CHIRP,
|
||||
USB_LINK_DEDICATED_CHG,
|
||||
USB_LINK_ACA_RID_A,
|
||||
USB_LINK_ACA_RID_B,
|
||||
USB_LINK_ACA_RID_C_NM,
|
||||
USB_LINK_ACA_RID_C_HS,
|
||||
USB_LINK_ACA_RID_C_HS_CHIRP,
|
||||
USB_LINK_HM_IDGND,
|
||||
USB_LINK_RESERVED,
|
||||
USB_LINK_NOT_VALID_LINK
|
||||
USB_LINK_NOT_CONFIGURED_8500 = 0,
|
||||
USB_LINK_STD_HOST_NC_8500,
|
||||
USB_LINK_STD_HOST_C_NS_8500,
|
||||
USB_LINK_STD_HOST_C_S_8500,
|
||||
USB_LINK_HOST_CHG_NM_8500,
|
||||
USB_LINK_HOST_CHG_HS_8500,
|
||||
USB_LINK_HOST_CHG_HS_CHIRP_8500,
|
||||
USB_LINK_DEDICATED_CHG_8500,
|
||||
USB_LINK_ACA_RID_A_8500,
|
||||
USB_LINK_ACA_RID_B_8500,
|
||||
USB_LINK_ACA_RID_C_NM_8500,
|
||||
USB_LINK_ACA_RID_C_HS_8500,
|
||||
USB_LINK_ACA_RID_C_HS_CHIRP_8500,
|
||||
USB_LINK_HM_IDGND_8500,
|
||||
USB_LINK_RESERVED_8500,
|
||||
USB_LINK_NOT_VALID_LINK_8500,
|
||||
};
|
||||
|
||||
enum ab8505_usb_link_status {
|
||||
USB_LINK_NOT_CONFIGURED_8505 = 0,
|
||||
USB_LINK_STD_HOST_NC_8505,
|
||||
USB_LINK_STD_HOST_C_NS_8505,
|
||||
USB_LINK_STD_HOST_C_S_8505,
|
||||
USB_LINK_CDP_8505,
|
||||
USB_LINK_RESERVED0_8505,
|
||||
USB_LINK_RESERVED1_8505,
|
||||
USB_LINK_DEDICATED_CHG_8505,
|
||||
USB_LINK_ACA_RID_A_8505,
|
||||
USB_LINK_ACA_RID_B_8505,
|
||||
USB_LINK_ACA_RID_C_NM_8505,
|
||||
USB_LINK_RESERVED2_8505,
|
||||
USB_LINK_RESERVED3_8505,
|
||||
USB_LINK_HM_IDGND_8505,
|
||||
USB_LINK_CHARGERPORT_NOT_OK_8505,
|
||||
USB_LINK_CHARGER_DM_HIGH_8505,
|
||||
USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505,
|
||||
USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505,
|
||||
USB_LINK_STD_UPSTREAM_8505,
|
||||
USB_LINK_CHARGER_SE1_8505,
|
||||
USB_LINK_CARKIT_CHGR_1_8505,
|
||||
USB_LINK_CARKIT_CHGR_2_8505,
|
||||
USB_LINK_ACA_DOCK_CHGR_8505,
|
||||
USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505,
|
||||
USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505,
|
||||
USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505,
|
||||
USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505,
|
||||
USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
|
||||
};
|
||||
|
||||
enum ab8500_usb_mode {
|
||||
USB_IDLE = 0,
|
||||
USB_PERIPHERAL,
|
||||
USB_HOST,
|
||||
USB_DEDICATED_CHG
|
||||
};
|
||||
|
||||
struct ab8500_usb {
|
||||
struct usb_phy phy;
|
||||
struct device *dev;
|
||||
struct ab8500 *ab8500;
|
||||
int irq_num_link_status;
|
||||
unsigned vbus_draw;
|
||||
struct delayed_work dwork;
|
||||
struct work_struct phy_dis_work;
|
||||
unsigned long link_status_wait;
|
||||
enum ab8500_usb_mode mode;
|
||||
int previous_link_status_state;
|
||||
};
|
||||
|
||||
static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
|
||||
|
@ -104,6 +146,17 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
|
|||
0);
|
||||
}
|
||||
|
||||
static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit)
|
||||
{
|
||||
/* Workaround for v2.0 bug # 31952 */
|
||||
if (is_ab8500_2p0(ab->ab8500)) {
|
||||
abx500_mask_and_set_register_interruptible(ab->dev,
|
||||
AB8500_USB, AB8500_USB_PHY_CTRL_REG,
|
||||
bit, bit);
|
||||
udelay(AB8500_V20_31952_DISABLE_DELAY_US);
|
||||
}
|
||||
}
|
||||
|
||||
static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
|
||||
bool enable)
|
||||
{
|
||||
|
@ -139,90 +192,274 @@ static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
|
|||
#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true)
|
||||
#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false)
|
||||
|
||||
static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
|
||||
static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
|
||||
enum ab8505_usb_link_status lsts)
|
||||
{
|
||||
u8 reg;
|
||||
enum ab8500_usb_link_status lsts;
|
||||
void *v = NULL;
|
||||
enum usb_phy_events event;
|
||||
enum ux500_musb_vbus_id_status event = 0;
|
||||
|
||||
abx500_get_register_interruptible(ab->dev,
|
||||
AB8500_USB,
|
||||
AB8500_USB_LINE_STAT_REG,
|
||||
®);
|
||||
dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts);
|
||||
|
||||
lsts = (reg >> 3) & 0x0F;
|
||||
/*
|
||||
* Spurious link_status interrupts are seen at the time of
|
||||
* disconnection of a device in RIDA state
|
||||
*/
|
||||
if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
|
||||
(lsts == USB_LINK_STD_HOST_NC_8505))
|
||||
return 0;
|
||||
|
||||
ab->previous_link_status_state = lsts;
|
||||
|
||||
switch (lsts) {
|
||||
case USB_LINK_NOT_CONFIGURED:
|
||||
case USB_LINK_RESERVED:
|
||||
case USB_LINK_NOT_VALID_LINK:
|
||||
/* TODO: Disable regulators. */
|
||||
ab8500_usb_host_phy_dis(ab);
|
||||
ab8500_usb_peri_phy_dis(ab);
|
||||
ab->phy.state = OTG_STATE_B_IDLE;
|
||||
case USB_LINK_ACA_RID_B_8505:
|
||||
event = UX500_MUSB_RIDB;
|
||||
case USB_LINK_NOT_CONFIGURED_8505:
|
||||
case USB_LINK_RESERVED0_8505:
|
||||
case USB_LINK_RESERVED1_8505:
|
||||
case USB_LINK_RESERVED2_8505:
|
||||
case USB_LINK_RESERVED3_8505:
|
||||
ab->mode = USB_IDLE;
|
||||
ab->phy.otg->default_a = false;
|
||||
ab->vbus_draw = 0;
|
||||
event = USB_EVENT_NONE;
|
||||
if (event != UX500_MUSB_RIDB)
|
||||
event = UX500_MUSB_NONE;
|
||||
/*
|
||||
* Fallback to default B_IDLE as nothing
|
||||
* is connected
|
||||
*/
|
||||
ab->phy.state = OTG_STATE_B_IDLE;
|
||||
break;
|
||||
|
||||
case USB_LINK_STD_HOST_NC:
|
||||
case USB_LINK_STD_HOST_C_NS:
|
||||
case USB_LINK_STD_HOST_C_S:
|
||||
case USB_LINK_HOST_CHG_NM:
|
||||
case USB_LINK_HOST_CHG_HS:
|
||||
case USB_LINK_HOST_CHG_HS_CHIRP:
|
||||
if (ab->phy.otg->gadget) {
|
||||
/* TODO: Enable regulators. */
|
||||
case USB_LINK_ACA_RID_C_NM_8505:
|
||||
event = UX500_MUSB_RIDC;
|
||||
case USB_LINK_STD_HOST_NC_8505:
|
||||
case USB_LINK_STD_HOST_C_NS_8505:
|
||||
case USB_LINK_STD_HOST_C_S_8505:
|
||||
case USB_LINK_CDP_8505:
|
||||
if (ab->mode == USB_IDLE) {
|
||||
ab->mode = USB_PERIPHERAL;
|
||||
ab8500_usb_peri_phy_en(ab);
|
||||
v = ab->phy.otg->gadget;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
UX500_MUSB_PREPARE, &ab->vbus_draw);
|
||||
}
|
||||
event = USB_EVENT_VBUS;
|
||||
if (event != UX500_MUSB_RIDC)
|
||||
event = UX500_MUSB_VBUS;
|
||||
break;
|
||||
|
||||
case USB_LINK_HM_IDGND:
|
||||
if (ab->phy.otg->host) {
|
||||
/* TODO: Enable regulators. */
|
||||
case USB_LINK_ACA_RID_A_8505:
|
||||
case USB_LINK_ACA_DOCK_CHGR_8505:
|
||||
event = UX500_MUSB_RIDA;
|
||||
case USB_LINK_HM_IDGND_8505:
|
||||
if (ab->mode == USB_IDLE) {
|
||||
ab->mode = USB_HOST;
|
||||
ab8500_usb_host_phy_en(ab);
|
||||
v = ab->phy.otg->host;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
UX500_MUSB_PREPARE, &ab->vbus_draw);
|
||||
}
|
||||
ab->phy.state = OTG_STATE_A_IDLE;
|
||||
ab->phy.otg->default_a = true;
|
||||
event = USB_EVENT_ID;
|
||||
if (event != UX500_MUSB_RIDA)
|
||||
event = UX500_MUSB_ID;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
break;
|
||||
|
||||
case USB_LINK_ACA_RID_A:
|
||||
case USB_LINK_ACA_RID_B:
|
||||
/* TODO */
|
||||
case USB_LINK_ACA_RID_C_NM:
|
||||
case USB_LINK_ACA_RID_C_HS:
|
||||
case USB_LINK_ACA_RID_C_HS_CHIRP:
|
||||
case USB_LINK_DEDICATED_CHG:
|
||||
/* TODO: vbus_draw */
|
||||
event = USB_EVENT_CHARGER;
|
||||
case USB_LINK_DEDICATED_CHG_8505:
|
||||
ab->mode = USB_DEDICATED_CHG;
|
||||
event = UX500_MUSB_CHARGER;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
atomic_notifier_call_chain(&ab->phy.notifier, event, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
|
||||
enum ab8500_usb_link_status lsts)
|
||||
{
|
||||
enum ux500_musb_vbus_id_status event = 0;
|
||||
|
||||
dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts);
|
||||
|
||||
/*
|
||||
* Spurious link_status interrupts are seen in case of a
|
||||
* disconnection of a device in IDGND and RIDA stage
|
||||
*/
|
||||
if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
|
||||
(lsts == USB_LINK_STD_HOST_C_NS_8500 ||
|
||||
lsts == USB_LINK_STD_HOST_NC_8500))
|
||||
return 0;
|
||||
|
||||
if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
|
||||
lsts == USB_LINK_STD_HOST_NC_8500)
|
||||
return 0;
|
||||
|
||||
ab->previous_link_status_state = lsts;
|
||||
|
||||
switch (lsts) {
|
||||
case USB_LINK_ACA_RID_B_8500:
|
||||
event = UX500_MUSB_RIDB;
|
||||
case USB_LINK_NOT_CONFIGURED_8500:
|
||||
case USB_LINK_NOT_VALID_LINK_8500:
|
||||
ab->mode = USB_IDLE;
|
||||
ab->phy.otg->default_a = false;
|
||||
ab->vbus_draw = 0;
|
||||
if (event != UX500_MUSB_RIDB)
|
||||
event = UX500_MUSB_NONE;
|
||||
/* Fallback to default B_IDLE as nothing is connected */
|
||||
ab->phy.state = OTG_STATE_B_IDLE;
|
||||
break;
|
||||
|
||||
case USB_LINK_ACA_RID_C_NM_8500:
|
||||
case USB_LINK_ACA_RID_C_HS_8500:
|
||||
case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
|
||||
event = UX500_MUSB_RIDC;
|
||||
case USB_LINK_STD_HOST_NC_8500:
|
||||
case USB_LINK_STD_HOST_C_NS_8500:
|
||||
case USB_LINK_STD_HOST_C_S_8500:
|
||||
case USB_LINK_HOST_CHG_NM_8500:
|
||||
case USB_LINK_HOST_CHG_HS_8500:
|
||||
case USB_LINK_HOST_CHG_HS_CHIRP_8500:
|
||||
if (ab->mode == USB_IDLE) {
|
||||
ab->mode = USB_PERIPHERAL;
|
||||
ab8500_usb_peri_phy_en(ab);
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
UX500_MUSB_PREPARE, &ab->vbus_draw);
|
||||
}
|
||||
if (event != UX500_MUSB_RIDC)
|
||||
event = UX500_MUSB_VBUS;
|
||||
break;
|
||||
|
||||
case USB_LINK_ACA_RID_A_8500:
|
||||
event = UX500_MUSB_RIDA;
|
||||
case USB_LINK_HM_IDGND_8500:
|
||||
if (ab->mode == USB_IDLE) {
|
||||
ab->mode = USB_HOST;
|
||||
ab8500_usb_host_phy_en(ab);
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
UX500_MUSB_PREPARE, &ab->vbus_draw);
|
||||
}
|
||||
ab->phy.otg->default_a = true;
|
||||
if (event != UX500_MUSB_RIDA)
|
||||
event = UX500_MUSB_ID;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
break;
|
||||
|
||||
case USB_LINK_DEDICATED_CHG_8500:
|
||||
ab->mode = USB_DEDICATED_CHG;
|
||||
event = UX500_MUSB_CHARGER;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
break;
|
||||
|
||||
case USB_LINK_RESERVED_8500:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connection Sequence:
|
||||
* 1. Link Status Interrupt
|
||||
* 2. Enable AB clock
|
||||
* 3. Enable AB regulators
|
||||
* 4. Enable USB phy
|
||||
* 5. Reset the musb controller
|
||||
* 6. Switch the ULPI GPIO pins to fucntion mode
|
||||
* 7. Enable the musb Peripheral5 clock
|
||||
* 8. Restore MUSB context
|
||||
*/
|
||||
static int abx500_usb_link_status_update(struct ab8500_usb *ab)
|
||||
{
|
||||
u8 reg;
|
||||
int ret = 0;
|
||||
|
||||
if (is_ab8500(ab->ab8500)) {
|
||||
enum ab8500_usb_link_status lsts;
|
||||
|
||||
abx500_get_register_interruptible(ab->dev,
|
||||
AB8500_USB, AB8500_USB_LINE_STAT_REG, ®);
|
||||
lsts = (reg >> 3) & 0x0F;
|
||||
ret = ab8500_usb_link_status_update(ab, lsts);
|
||||
} else if (is_ab8505(ab->ab8500)) {
|
||||
enum ab8505_usb_link_status lsts;
|
||||
|
||||
abx500_get_register_interruptible(ab->dev,
|
||||
AB8500_USB, AB8505_USB_LINE_STAT_REG, ®);
|
||||
lsts = (reg >> 3) & 0x1F;
|
||||
ret = ab8505_usb_link_status_update(ab, lsts);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnection Sequence:
|
||||
* 1. Disconect Interrupt
|
||||
* 2. Disable regulators
|
||||
* 3. Disable AB clock
|
||||
* 4. Disable the Phy
|
||||
* 5. Link Status Interrupt
|
||||
* 6. Disable Musb Clock
|
||||
*/
|
||||
static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
|
||||
{
|
||||
struct ab8500_usb *ab = (struct ab8500_usb *) data;
|
||||
enum usb_phy_events event = UX500_MUSB_NONE;
|
||||
|
||||
/* Link status will not be updated till phy is disabled. */
|
||||
if (ab->mode == USB_HOST) {
|
||||
ab->phy.otg->default_a = false;
|
||||
ab->vbus_draw = 0;
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
ab8500_usb_host_phy_dis(ab);
|
||||
ab->mode = USB_IDLE;
|
||||
}
|
||||
|
||||
if (ab->mode == USB_PERIPHERAL) {
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
event, &ab->vbus_draw);
|
||||
ab8500_usb_peri_phy_dis(ab);
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
UX500_MUSB_CLEAN, &ab->vbus_draw);
|
||||
ab->mode = USB_IDLE;
|
||||
ab->phy.otg->default_a = false;
|
||||
ab->vbus_draw = 0;
|
||||
}
|
||||
|
||||
if (is_ab8500_2p0(ab->ab8500)) {
|
||||
if (ab->mode == USB_DEDICATED_CHG) {
|
||||
ab8500_usb_wd_linkstatus(ab,
|
||||
AB8500_BIT_PHY_CTRL_DEVICE_EN);
|
||||
abx500_mask_and_set_register_interruptible(ab->dev,
|
||||
AB8500_USB, AB8500_USB_PHY_CTRL_REG,
|
||||
AB8500_BIT_PHY_CTRL_DEVICE_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
|
||||
{
|
||||
struct ab8500_usb *ab = (struct ab8500_usb *) data;
|
||||
|
||||
abx500_usb_link_status_update(ab);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void ab8500_usb_delayed_work(struct work_struct *work)
|
||||
{
|
||||
struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
|
||||
dwork.work);
|
||||
|
||||
ab8500_usb_link_status_update(ab);
|
||||
}
|
||||
|
||||
static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
|
||||
{
|
||||
struct ab8500_usb *ab = (struct ab8500_usb *) data;
|
||||
|
||||
ab8500_usb_link_status_update(ab);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
abx500_usb_link_status_update(ab);
|
||||
}
|
||||
|
||||
static void ab8500_usb_phy_disable_work(struct work_struct *work)
|
||||
|
@ -250,7 +487,7 @@ static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
|
|||
|
||||
if (mA)
|
||||
atomic_notifier_call_chain(&ab->phy.notifier,
|
||||
USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
|
||||
UX500_MUSB_ENUMERATED, ab->phy.otg->gadget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -327,30 +564,48 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ab8500_usb_irq_free(struct ab8500_usb *ab)
|
||||
{
|
||||
free_irq(ab->irq_num_link_status, ab);
|
||||
}
|
||||
|
||||
static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
|
||||
struct ab8500_usb *ab)
|
||||
static int ab8500_usb_irq_setup(struct platform_device *pdev,
|
||||
struct ab8500_usb *ab)
|
||||
{
|
||||
int err;
|
||||
int irq;
|
||||
|
||||
ab->irq_num_link_status = platform_get_irq_byname(pdev,
|
||||
"USB_LINK_STATUS");
|
||||
if (ab->irq_num_link_status < 0) {
|
||||
irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS");
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Link status irq not found\n");
|
||||
return ab->irq_num_link_status;
|
||||
return irq;
|
||||
}
|
||||
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
ab8500_usb_link_status_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab);
|
||||
if (err < 0) {
|
||||
dev_err(ab->dev, "request_irq failed for link status irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = request_threaded_irq(ab->irq_num_link_status, NULL,
|
||||
ab8500_usb_v20_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED,
|
||||
"usb-link-status", ab);
|
||||
irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "ID fall irq not found\n");
|
||||
return irq;
|
||||
}
|
||||
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
ab8500_usb_disconnect_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab);
|
||||
if (err < 0) {
|
||||
dev_err(ab->dev,
|
||||
"request_irq failed for link status irq\n");
|
||||
dev_err(ab->dev, "request_irq failed for ID fall irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "VBUS_DET_F");
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "VBUS fall irq not found\n");
|
||||
return irq;
|
||||
}
|
||||
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
ab8500_usb_disconnect_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab);
|
||||
if (err < 0) {
|
||||
dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -408,22 +663,23 @@ static int ab8500_usb_probe(struct platform_device *pdev)
|
|||
/* all: Disable phy when called from set_host and set_peripheral */
|
||||
INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
|
||||
|
||||
err = ab8500_usb_v2_res_setup(pdev, ab);
|
||||
err = ab8500_usb_irq_setup(pdev, ab);
|
||||
if (err < 0)
|
||||
goto fail0;
|
||||
goto fail;
|
||||
|
||||
err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Can't register transceiver\n");
|
||||
goto fail1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Needed to enable ID detection. */
|
||||
ab8500_usb_wd_workaround(ab);
|
||||
|
||||
dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
|
||||
|
||||
return 0;
|
||||
fail1:
|
||||
ab8500_usb_irq_free(ab);
|
||||
fail0:
|
||||
fail:
|
||||
kfree(otg);
|
||||
kfree(ab);
|
||||
return err;
|
||||
|
@ -433,8 +689,6 @@ static int ab8500_usb_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ab8500_usb *ab = platform_get_drvdata(pdev);
|
||||
|
||||
ab8500_usb_irq_free(ab);
|
||||
|
||||
cancel_delayed_work_sync(&ab->dwork);
|
||||
|
||||
cancel_work_sync(&ab->phy_dis_work);
|
||||
|
|
31
include/linux/usb/musb-ux500.h
Normal file
31
include/linux/usb/musb-ux500.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2013 ST-Ericsson AB
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_UX500_H__
|
||||
#define __MUSB_UX500_H__
|
||||
|
||||
enum ux500_musb_vbus_id_status {
|
||||
UX500_MUSB_NONE = 0,
|
||||
UX500_MUSB_VBUS,
|
||||
UX500_MUSB_ID,
|
||||
UX500_MUSB_CHARGER,
|
||||
UX500_MUSB_ENUMERATED,
|
||||
UX500_MUSB_RIDA,
|
||||
UX500_MUSB_RIDB,
|
||||
UX500_MUSB_RIDC,
|
||||
UX500_MUSB_PREPARE,
|
||||
UX500_MUSB_CLEAN,
|
||||
};
|
||||
|
||||
#endif /* __MUSB_UX500_H__ */
|
Loading…
Reference in New Issue
Block a user