usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB.
Properly triggering the reset wire is necessary with the ISP1761 used on Terasic DE4 Altera-FPGA boards using a NIOS2 processor, for example. This is an optional implementation for the OF binding only. The other bindings just pass an invalid GPIO to the isp1760_register() routine. Example, usage in DTS: gpios = <&pio_isp1761rst_0 0 1>; to point to a GPIO controller from within the ISP1761 node: GPIO 0, active low. Signed-off-by: Joachim Foerster <joachim.foerster@missinglinkelectronics.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
0f8fd43c42
commit
3a7655fcb2
|
@ -24,6 +24,7 @@
|
|||
#include <linux/timer.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "isp1760-hcd.h"
|
||||
|
||||
|
@ -48,6 +49,8 @@ struct isp1760_hcd {
|
|||
unsigned long reset_done;
|
||||
unsigned long next_statechange;
|
||||
unsigned int devflags;
|
||||
|
||||
int rst_gpio;
|
||||
};
|
||||
|
||||
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
|
||||
|
@ -433,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
|||
int result;
|
||||
u32 scratch, hwmode;
|
||||
|
||||
/* low-level chip reset */
|
||||
if (gpio_is_valid(priv->rst_gpio)) {
|
||||
unsigned int rst_lvl;
|
||||
|
||||
rst_lvl = (priv->devflags &
|
||||
ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
|
||||
|
||||
gpio_set_value(priv->rst_gpio, rst_lvl);
|
||||
mdelay(50);
|
||||
gpio_set_value(priv->rst_gpio, !rst_lvl);
|
||||
}
|
||||
|
||||
/* Setup HW Mode Control: This assumes a level active-low interrupt */
|
||||
hwmode = HW_DATA_BUS_32BIT;
|
||||
|
||||
|
@ -2207,6 +2222,7 @@ void deinit_kmem_cache(void)
|
|||
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
int rst_gpio,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags)
|
||||
{
|
||||
|
@ -2226,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
|||
|
||||
priv = hcd_to_priv(hcd);
|
||||
priv->devflags = devflags;
|
||||
priv->rst_gpio = rst_gpio;
|
||||
init_memory(priv);
|
||||
hcd->regs = ioremap(res_start, res_len);
|
||||
if (!hcd->regs) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/* exports for if */
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
int rst_gpio,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags);
|
||||
int init_kmem_once(void);
|
||||
|
@ -126,6 +127,7 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
|||
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
|
||||
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
|
||||
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
|
||||
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
|
||||
|
||||
/* chip memory management */
|
||||
struct memory_chunk {
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
#include "isp1760-hcd.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -29,9 +31,14 @@
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct isp1760 {
|
||||
struct usb_hcd *hcd;
|
||||
int rst_gpio;
|
||||
};
|
||||
|
||||
static int of_isp1760_probe(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct isp1760 *drvdata;
|
||||
struct device_node *dp = dev->dev.of_node;
|
||||
struct resource *res;
|
||||
struct resource memory;
|
||||
|
@ -41,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev)
|
|||
int ret;
|
||||
const unsigned int *prop;
|
||||
unsigned int devflags = 0;
|
||||
enum of_gpio_flags gpio_flags;
|
||||
|
||||
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(dp, 0, &memory);
|
||||
if (ret)
|
||||
|
@ -80,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev)
|
|||
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
|
||||
|
||||
hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED, &dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret = PTR_ERR(hcd);
|
||||
goto release_reg;
|
||||
drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
|
||||
if (gpio_is_valid(drvdata->rst_gpio)) {
|
||||
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
|
||||
if (!ret) {
|
||||
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
|
||||
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
|
||||
gpio_direction_output(drvdata->rst_gpio, 0);
|
||||
} else {
|
||||
gpio_direction_output(drvdata->rst_gpio, 1);
|
||||
}
|
||||
} else {
|
||||
drvdata->rst_gpio = ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dev->dev, hcd);
|
||||
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED, drvdata->rst_gpio,
|
||||
&dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(drvdata->hcd)) {
|
||||
ret = PTR_ERR(drvdata->hcd);
|
||||
goto free_gpio;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dev->dev, drvdata);
|
||||
return ret;
|
||||
|
||||
free_gpio:
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
release_reg:
|
||||
release_mem_region(memory.start, res_len);
|
||||
kfree(drvdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int of_isp1760_remove(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
|
||||
struct isp1760 *drvdata = dev_get_drvdata(&dev->dev);
|
||||
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
usb_remove_hcd(drvdata->hcd);
|
||||
iounmap(drvdata->hcd->regs);
|
||||
release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
|
||||
usb_put_hcd(drvdata->hcd);
|
||||
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -242,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
|
|||
|
||||
dev->dev.dma_mask = NULL;
|
||||
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
|
||||
IRQF_SHARED, &dev->dev, dev_name(&dev->dev),
|
||||
IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret_status = -ENODEV;
|
||||
|
@ -353,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
|
||||
irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
|
||||
irqflags, -ENOENT,
|
||||
&pdev->dev, dev_name(&pdev->dev), devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
pr_warning("isp1760: Failed to register the HCD device\n");
|
||||
ret = -ENODEV;
|
||||
|
|
Loading…
Reference in New Issue