Merge branch 'next/devel' of git://git.linaro.org/people/arnd/arm-soc
* 'next/devel' of git://git.linaro.org/people/arnd/arm-soc: (50 commits) ARM: tegra: update defconfig arm/tegra: Harmony: Configure PMC for low-level interrupts arm/tegra: device tree support for ventana board arm/tegra: add support for ventana pinmuxing arm/tegra: prepare Seaboard pinmux code for derived boards arm/tegra: pinmux: ioremap registers gpio/tegra: Convert to a platform device arm/tegra: Convert pinmux driver to a platform device arm/dt: Tegra: Add pinmux node to tegra20.dtsi arm/tegra: Prep boards for gpio/pinmux conversion to pdevs ARM: mx5: fix clock usage for suspend ARM i.MX entry-macro.S: remove now unused code ARM i.MX boards: use CONFIG_MULTI_IRQ_HANDLER ARM i.MX tzic: add handle_irq function ARM i.MX avic: add handle_irq function ARM: mx25: Add the missing IIM base definition ARM i.MX avic: convert to use generic irq chip mx31moboard: Add poweroff support ARM: mach-qong: Add watchdog support ARM: davinci: AM18x: Add wl1271/wlan support ... Fix up conflicts in: arch/arm/mach-at91/at91sam9g45.c arch/arm/mach-mx5/devices-imx53.h arch/arm/plat-mxc/include/mach/memory.h
This commit is contained in:
@@ -35,8 +35,7 @@ extern int usb_disabled(void);
|
||||
|
||||
static void at91_start_clock(void)
|
||||
{
|
||||
if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
|
||||
clk_enable(hclk);
|
||||
clk_enable(hclk);
|
||||
clk_enable(iclk);
|
||||
clk_enable(fclk);
|
||||
clocked = 1;
|
||||
@@ -46,8 +45,7 @@ static void at91_stop_clock(void)
|
||||
{
|
||||
clk_disable(fclk);
|
||||
clk_disable(iclk);
|
||||
if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
|
||||
clk_disable(hclk);
|
||||
clk_disable(hclk);
|
||||
clocked = 0;
|
||||
}
|
||||
|
||||
@@ -142,8 +140,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
||||
|
||||
iclk = clk_get(&pdev->dev, "ohci_clk");
|
||||
fclk = clk_get(&pdev->dev, "uhpck");
|
||||
if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
|
||||
hclk = clk_get(&pdev->dev, "hck0");
|
||||
hclk = clk_get(&pdev->dev, "hclk");
|
||||
|
||||
at91_start_hc(pdev);
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
@@ -155,8 +152,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
||||
/* Error handling */
|
||||
at91_stop_hc(pdev);
|
||||
|
||||
if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
|
||||
clk_put(hclk);
|
||||
clk_put(hclk);
|
||||
clk_put(fclk);
|
||||
clk_put(iclk);
|
||||
|
||||
@@ -192,8 +188,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
if (cpu_is_at91sam9261() || cpu_is_at91sam9g10())
|
||||
clk_put(hclk);
|
||||
clk_put(hclk);
|
||||
clk_put(fclk);
|
||||
clk_put(iclk);
|
||||
fclk = iclk = hclk = NULL;
|
||||
@@ -223,6 +218,156 @@ ohci_at91_start (struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)
|
||||
{
|
||||
if (port < 0 || port >= 2)
|
||||
return;
|
||||
|
||||
gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable);
|
||||
}
|
||||
|
||||
static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
|
||||
{
|
||||
if (port < 0 || port >= 2)
|
||||
return -EINVAL;
|
||||
|
||||
return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the status data from the hub with the over-current indicator change.
|
||||
*/
|
||||
static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
|
||||
{
|
||||
struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
|
||||
int length = ohci_hub_status_data(hcd, buf);
|
||||
int port;
|
||||
|
||||
for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
|
||||
if (pdata->overcurrent_changed[port]) {
|
||||
if (! length)
|
||||
length = 1;
|
||||
buf[0] |= 1 << (port + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at the control requests to the root hub and see if we need to override.
|
||||
*/
|
||||
static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
u16 wIndex, char *buf, u16 wLength)
|
||||
{
|
||||
struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
|
||||
struct usb_hub_descriptor *desc;
|
||||
int ret = -EINVAL;
|
||||
u32 *data = (u32 *)buf;
|
||||
|
||||
dev_dbg(hcd->self.controller,
|
||||
"ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
|
||||
hcd, typeReq, wValue, wIndex, buf, wLength);
|
||||
|
||||
switch (typeReq) {
|
||||
case SetPortFeature:
|
||||
if (wValue == USB_PORT_FEAT_POWER) {
|
||||
dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
|
||||
ohci_at91_usb_set_power(pdata, wIndex - 1, 1);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case ClearPortFeature:
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
dev_dbg(hcd->self.controller,
|
||||
"ClearPortFeature: C_OVER_CURRENT\n");
|
||||
|
||||
if (wIndex == 1 || wIndex == 2) {
|
||||
pdata->overcurrent_changed[wIndex-1] = 0;
|
||||
pdata->overcurrent_status[wIndex-1] = 0;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
case USB_PORT_FEAT_OVER_CURRENT:
|
||||
dev_dbg(hcd->self.controller,
|
||||
"ClearPortFeature: OVER_CURRENT\n");
|
||||
|
||||
if (wIndex == 1 || wIndex == 2) {
|
||||
pdata->overcurrent_status[wIndex-1] = 0;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
case USB_PORT_FEAT_POWER:
|
||||
dev_dbg(hcd->self.controller,
|
||||
"ClearPortFeature: POWER\n");
|
||||
|
||||
if (wIndex == 1 || wIndex == 2) {
|
||||
ohci_at91_usb_set_power(pdata, wIndex - 1, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
switch (typeReq) {
|
||||
case GetHubDescriptor:
|
||||
|
||||
/* update the hub's descriptor */
|
||||
|
||||
desc = (struct usb_hub_descriptor *)buf;
|
||||
|
||||
dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n",
|
||||
desc->wHubCharacteristics);
|
||||
|
||||
/* remove the old configurations for power-switching, and
|
||||
* over-current protection, and insert our new configuration
|
||||
*/
|
||||
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
|
||||
|
||||
if (pdata->overcurrent_supported) {
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
|
||||
}
|
||||
|
||||
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
|
||||
desc->wHubCharacteristics);
|
||||
|
||||
return ret;
|
||||
|
||||
case GetPortStatus:
|
||||
/* check port status */
|
||||
|
||||
dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
|
||||
|
||||
if (wIndex == 1 || wIndex == 2) {
|
||||
if (! ohci_at91_usb_get_power(pdata, wIndex-1)) {
|
||||
*data &= ~cpu_to_le32(RH_PS_PPS);
|
||||
}
|
||||
|
||||
if (pdata->overcurrent_changed[wIndex-1]) {
|
||||
*data |= cpu_to_le32(RH_PS_OCIC);
|
||||
}
|
||||
|
||||
if (pdata->overcurrent_status[wIndex-1]) {
|
||||
*data |= cpu_to_le32(RH_PS_POCI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static const struct hc_driver ohci_at91_hc_driver = {
|
||||
@@ -258,8 +403,8 @@ static const struct hc_driver ohci_at91_hc_driver = {
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
.hub_status_data = ohci_at91_hub_status_data,
|
||||
.hub_control = ohci_at91_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ohci_bus_suspend,
|
||||
.bus_resume = ohci_bus_resume,
|
||||
@@ -269,22 +414,71 @@ static const struct hc_driver ohci_at91_hc_driver = {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
struct at91_usbh_data *pdata = pdev->dev.platform_data;
|
||||
int val, gpio, port;
|
||||
|
||||
/* From the GPIO notifying the over-current situation, find
|
||||
* out the corresponding port */
|
||||
gpio = irq_to_gpio(irq);
|
||||
for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
|
||||
if (pdata->overcurrent_pin[port] == gpio)
|
||||
break;
|
||||
}
|
||||
|
||||
if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
|
||||
dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
val = gpio_get_value(gpio);
|
||||
|
||||
/* When notified of an over-current situation, disable power
|
||||
on the corresponding port, and mark this port in
|
||||
over-current. */
|
||||
if (! val) {
|
||||
ohci_at91_usb_set_power(pdata, port, 0);
|
||||
pdata->overcurrent_status[port] = 1;
|
||||
pdata->overcurrent_changed[port] = 1;
|
||||
}
|
||||
|
||||
dev_dbg(& pdev->dev, "overcurrent situation %s\n",
|
||||
val ? "exited" : "notified");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_usbh_data *pdata = pdev->dev.platform_data;
|
||||
int i;
|
||||
|
||||
if (pdata) {
|
||||
/* REVISIT make the driver support per-port power switching,
|
||||
* and also overcurrent detection. Here we assume the ports
|
||||
* are always powered while this driver is active, and use
|
||||
* active-low power switches.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
|
||||
if (pdata->vbus_pin[i] <= 0)
|
||||
continue;
|
||||
gpio_request(pdata->vbus_pin[i], "ohci_vbus");
|
||||
gpio_direction_output(pdata->vbus_pin[i], 0);
|
||||
ohci_at91_usb_set_power(pdata, i, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
|
||||
int ret;
|
||||
|
||||
if (pdata->overcurrent_pin[i] <= 0)
|
||||
continue;
|
||||
gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent");
|
||||
|
||||
ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]),
|
||||
ohci_hcd_at91_overcurrent_irq,
|
||||
IRQF_SHARED, "ohci_overcurrent", pdev);
|
||||
if (ret) {
|
||||
gpio_free(pdata->overcurrent_pin[i]);
|
||||
dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,9 +495,16 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
|
||||
if (pdata->vbus_pin[i] <= 0)
|
||||
continue;
|
||||
gpio_direction_output(pdata->vbus_pin[i], 1);
|
||||
ohci_at91_usb_set_power(pdata, i, 0);
|
||||
gpio_free(pdata->vbus_pin[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
|
||||
if (pdata->overcurrent_pin[i] <= 0)
|
||||
continue;
|
||||
free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev);
|
||||
gpio_free(pdata->overcurrent_pin[i]);
|
||||
}
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
Reference in New Issue
Block a user