|
@@ -2184,51 +2184,67 @@ static void macb_probe_queues(void __iomem *mem,
|
|
|
(*num_queues)++;
|
|
|
}
|
|
|
|
|
|
-static int macb_init(struct platform_device *pdev)
|
|
|
+static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
|
|
|
+ struct clk **hclk, struct clk **tx_clk)
|
|
|
{
|
|
|
- struct net_device *dev = platform_get_drvdata(pdev);
|
|
|
- unsigned int hw_q, q;
|
|
|
- struct macb *bp = netdev_priv(dev);
|
|
|
- struct macb_queue *queue;
|
|
|
int err;
|
|
|
- u32 val;
|
|
|
|
|
|
- bp->pclk = devm_clk_get(&pdev->dev, "pclk");
|
|
|
- if (IS_ERR(bp->pclk)) {
|
|
|
- err = PTR_ERR(bp->pclk);
|
|
|
+ *pclk = devm_clk_get(&pdev->dev, "pclk");
|
|
|
+ if (IS_ERR(*pclk)) {
|
|
|
+ err = PTR_ERR(*pclk);
|
|
|
dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- bp->hclk = devm_clk_get(&pdev->dev, "hclk");
|
|
|
- if (IS_ERR(bp->hclk)) {
|
|
|
- err = PTR_ERR(bp->hclk);
|
|
|
+ *hclk = devm_clk_get(&pdev->dev, "hclk");
|
|
|
+ if (IS_ERR(*hclk)) {
|
|
|
+ err = PTR_ERR(*hclk);
|
|
|
dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk");
|
|
|
- if (IS_ERR(bp->tx_clk))
|
|
|
- bp->tx_clk = NULL;
|
|
|
+ *tx_clk = devm_clk_get(&pdev->dev, "tx_clk");
|
|
|
+ if (IS_ERR(*tx_clk))
|
|
|
+ *tx_clk = NULL;
|
|
|
|
|
|
- err = clk_prepare_enable(bp->pclk);
|
|
|
+ err = clk_prepare_enable(*pclk);
|
|
|
if (err) {
|
|
|
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- err = clk_prepare_enable(bp->hclk);
|
|
|
+ err = clk_prepare_enable(*hclk);
|
|
|
if (err) {
|
|
|
dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err);
|
|
|
goto err_disable_pclk;
|
|
|
}
|
|
|
|
|
|
- err = clk_prepare_enable(bp->tx_clk);
|
|
|
+ err = clk_prepare_enable(*tx_clk);
|
|
|
if (err) {
|
|
|
dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
|
|
|
goto err_disable_hclk;
|
|
|
}
|
|
|
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_disable_hclk:
|
|
|
+ clk_disable_unprepare(*hclk);
|
|
|
+
|
|
|
+err_disable_pclk:
|
|
|
+ clk_disable_unprepare(*pclk);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int macb_init(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct net_device *dev = platform_get_drvdata(pdev);
|
|
|
+ unsigned int hw_q, q;
|
|
|
+ struct macb *bp = netdev_priv(dev);
|
|
|
+ struct macb_queue *queue;
|
|
|
+ int err;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
/* set the queue register mapping once for all: queue0 has a special
|
|
|
* register mapping but we don't want to test the queue index then
|
|
|
* compute the corresponding register offset at run time.
|
|
@@ -2266,7 +2282,7 @@ static int macb_init(struct platform_device *pdev)
|
|
|
dev_err(&pdev->dev,
|
|
|
"Unable to request IRQ %d (error %d)\n",
|
|
|
queue->irq, err);
|
|
|
- goto err_disable_tx_clk;
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
|
|
@@ -2322,17 +2338,6 @@ static int macb_init(struct platform_device *pdev)
|
|
|
macb_writel(bp, NCFGR, val);
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-err_disable_tx_clk:
|
|
|
- clk_disable_unprepare(bp->tx_clk);
|
|
|
-
|
|
|
-err_disable_hclk:
|
|
|
- clk_disable_unprepare(bp->hclk);
|
|
|
-
|
|
|
-err_disable_pclk:
|
|
|
- clk_disable_unprepare(bp->pclk);
|
|
|
-
|
|
|
- return err;
|
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_OF)
|
|
@@ -2600,30 +2605,41 @@ static const struct net_device_ops at91ether_netdev_ops = {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
-static int at91ether_init(struct platform_device *pdev)
|
|
|
+static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk,
|
|
|
+ struct clk **hclk, struct clk **tx_clk)
|
|
|
{
|
|
|
- struct net_device *dev = platform_get_drvdata(pdev);
|
|
|
- struct macb *bp = netdev_priv(dev);
|
|
|
int err;
|
|
|
- u32 reg;
|
|
|
|
|
|
- bp->pclk = devm_clk_get(&pdev->dev, "ether_clk");
|
|
|
- if (IS_ERR(bp->pclk))
|
|
|
- return PTR_ERR(bp->pclk);
|
|
|
+ *hclk = NULL;
|
|
|
+ *tx_clk = NULL;
|
|
|
+
|
|
|
+ *pclk = devm_clk_get(&pdev->dev, "ether_clk");
|
|
|
+ if (IS_ERR(*pclk))
|
|
|
+ return PTR_ERR(*pclk);
|
|
|
|
|
|
- err = clk_prepare_enable(bp->pclk);
|
|
|
+ err = clk_prepare_enable(*pclk);
|
|
|
if (err) {
|
|
|
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int at91ether_init(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct net_device *dev = platform_get_drvdata(pdev);
|
|
|
+ struct macb *bp = netdev_priv(dev);
|
|
|
+ int err;
|
|
|
+ u32 reg;
|
|
|
+
|
|
|
dev->netdev_ops = &at91ether_netdev_ops;
|
|
|
dev->ethtool_ops = &macb_ethtool_ops;
|
|
|
|
|
|
err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt,
|
|
|
0, dev->name, dev);
|
|
|
if (err)
|
|
|
- goto err_disable_clk;
|
|
|
+ return err;
|
|
|
|
|
|
macb_writel(bp, NCR, 0);
|
|
|
|
|
@@ -2634,37 +2650,37 @@ static int at91ether_init(struct platform_device *pdev)
|
|
|
macb_writel(bp, NCFGR, reg);
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-err_disable_clk:
|
|
|
- clk_disable_unprepare(bp->pclk);
|
|
|
-
|
|
|
- return err;
|
|
|
}
|
|
|
|
|
|
static const struct macb_config at91sam9260_config = {
|
|
|
.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII,
|
|
|
+ .clk_init = macb_clk_init,
|
|
|
.init = macb_init,
|
|
|
};
|
|
|
|
|
|
static const struct macb_config pc302gem_config = {
|
|
|
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
|
|
|
.dma_burst_length = 16,
|
|
|
+ .clk_init = macb_clk_init,
|
|
|
.init = macb_init,
|
|
|
};
|
|
|
|
|
|
static const struct macb_config sama5d3_config = {
|
|
|
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
|
|
|
.dma_burst_length = 16,
|
|
|
+ .clk_init = macb_clk_init,
|
|
|
.init = macb_init,
|
|
|
};
|
|
|
|
|
|
static const struct macb_config sama5d4_config = {
|
|
|
.caps = 0,
|
|
|
.dma_burst_length = 4,
|
|
|
+ .clk_init = macb_clk_init,
|
|
|
.init = macb_init,
|
|
|
};
|
|
|
|
|
|
static const struct macb_config emac_config = {
|
|
|
+ .clk_init = at91ether_clk_init,
|
|
|
.init = at91ether_init,
|
|
|
};
|
|
|
|
|
@@ -2685,9 +2701,13 @@ MODULE_DEVICE_TABLE(of, macb_dt_ids);
|
|
|
|
|
|
static int macb_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
+ int (*clk_init)(struct platform_device *, struct clk **,
|
|
|
+ struct clk **, struct clk **)
|
|
|
+ = macb_clk_init;
|
|
|
int (*init)(struct platform_device *) = macb_init;
|
|
|
struct device_node *np = pdev->dev.of_node;
|
|
|
const struct macb_config *macb_config = NULL;
|
|
|
+ struct clk *pclk, *hclk, *tx_clk;
|
|
|
unsigned int queue_mask, num_queues;
|
|
|
struct macb_platform_data *pdata;
|
|
|
struct phy_device *phydev;
|
|
@@ -2698,15 +2718,34 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
struct macb *bp;
|
|
|
int err;
|
|
|
|
|
|
+ if (np) {
|
|
|
+ const struct of_device_id *match;
|
|
|
+
|
|
|
+ match = of_match_node(macb_dt_ids, np);
|
|
|
+ if (match && match->data) {
|
|
|
+ macb_config = match->data;
|
|
|
+ clk_init = macb_config->clk_init;
|
|
|
+ init = macb_config->init;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ err = clk_init(pdev, &pclk, &hclk, &tx_clk);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
mem = devm_ioremap_resource(&pdev->dev, regs);
|
|
|
- if (IS_ERR(mem))
|
|
|
- return PTR_ERR(mem);
|
|
|
+ if (IS_ERR(mem)) {
|
|
|
+ err = PTR_ERR(mem);
|
|
|
+ goto err_disable_clocks;
|
|
|
+ }
|
|
|
|
|
|
macb_probe_queues(mem, &queue_mask, &num_queues);
|
|
|
dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
|
|
|
- if (!dev)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!dev) {
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto err_disable_clocks;
|
|
|
+ }
|
|
|
|
|
|
dev->base_addr = regs->start;
|
|
|
|
|
@@ -2718,27 +2757,23 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
bp->regs = mem;
|
|
|
bp->num_queues = num_queues;
|
|
|
bp->queue_mask = queue_mask;
|
|
|
+ if (macb_config)
|
|
|
+ bp->dma_burst_length = macb_config->dma_burst_length;
|
|
|
+ bp->pclk = pclk;
|
|
|
+ bp->hclk = hclk;
|
|
|
+ bp->tx_clk = tx_clk;
|
|
|
spin_lock_init(&bp->lock);
|
|
|
|
|
|
- if (np) {
|
|
|
- const struct of_device_id *match;
|
|
|
-
|
|
|
- match = of_match_node(macb_dt_ids, np);
|
|
|
- if (match && match->data) {
|
|
|
- macb_config = match->data;
|
|
|
- bp->dma_burst_length = macb_config->dma_burst_length;
|
|
|
- init = macb_config->init;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/* setup capabilities */
|
|
|
macb_configure_caps(bp, macb_config);
|
|
|
|
|
|
platform_set_drvdata(pdev, dev);
|
|
|
|
|
|
dev->irq = platform_get_irq(pdev, 0);
|
|
|
- if (dev->irq < 0)
|
|
|
- return dev->irq;
|
|
|
+ if (dev->irq < 0) {
|
|
|
+ err = dev->irq;
|
|
|
+ goto err_disable_clocks;
|
|
|
+ }
|
|
|
|
|
|
mac = of_get_mac_address(np);
|
|
|
if (mac)
|
|
@@ -2765,7 +2800,7 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
err = register_netdev(dev);
|
|
|
if (err) {
|
|
|
dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
|
|
|
- goto err_disable_clocks;
|
|
|
+ goto err_out_unregister_netdev;
|
|
|
}
|
|
|
|
|
|
err = macb_mii_init(bp);
|
|
@@ -2787,14 +2822,14 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
err_out_unregister_netdev:
|
|
|
unregister_netdev(dev);
|
|
|
|
|
|
-err_disable_clocks:
|
|
|
- clk_disable_unprepare(bp->tx_clk);
|
|
|
- clk_disable_unprepare(bp->hclk);
|
|
|
- clk_disable_unprepare(bp->pclk);
|
|
|
-
|
|
|
err_out_free_netdev:
|
|
|
free_netdev(dev);
|
|
|
|
|
|
+err_disable_clocks:
|
|
|
+ clk_disable_unprepare(tx_clk);
|
|
|
+ clk_disable_unprepare(hclk);
|
|
|
+ clk_disable_unprepare(pclk);
|
|
|
+
|
|
|
return err;
|
|
|
}
|
|
|
|