Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dev-enet.c
Go to the documentation of this file.
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License. See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2008 Maxime Bizon <[email protected]>
7  */
8 
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/platform_device.h>
12 #include <bcm63xx_dev_enet.h>
13 #include <bcm63xx_io.h>
14 #include <bcm63xx_regs.h>
15 
16 static struct resource shared_res[] = {
17  {
18  .start = -1, /* filled at runtime */
19  .end = -1, /* filled at runtime */
20  .flags = IORESOURCE_MEM,
21  },
22 };
23 
24 static struct platform_device bcm63xx_enet_shared_device = {
25  .name = "bcm63xx_enet_shared",
26  .id = 0,
27  .num_resources = ARRAY_SIZE(shared_res),
28  .resource = shared_res,
29 };
30 
31 static int shared_device_registered;
32 
33 static struct resource enet0_res[] = {
34  {
35  .start = -1, /* filled at runtime */
36  .end = -1, /* filled at runtime */
37  .flags = IORESOURCE_MEM,
38  },
39  {
40  .start = -1, /* filled at runtime */
41  .flags = IORESOURCE_IRQ,
42  },
43  {
44  .start = -1, /* filled at runtime */
45  .flags = IORESOURCE_IRQ,
46  },
47  {
48  .start = -1, /* filled at runtime */
49  .flags = IORESOURCE_IRQ,
50  },
51 };
52 
53 static struct bcm63xx_enet_platform_data enet0_pd;
54 
55 static struct platform_device bcm63xx_enet0_device = {
56  .name = "bcm63xx_enet",
57  .id = 0,
58  .num_resources = ARRAY_SIZE(enet0_res),
59  .resource = enet0_res,
60  .dev = {
61  .platform_data = &enet0_pd,
62  },
63 };
64 
65 static struct resource enet1_res[] = {
66  {
67  .start = -1, /* filled at runtime */
68  .end = -1, /* filled at runtime */
69  .flags = IORESOURCE_MEM,
70  },
71  {
72  .start = -1, /* filled at runtime */
73  .flags = IORESOURCE_IRQ,
74  },
75  {
76  .start = -1, /* filled at runtime */
77  .flags = IORESOURCE_IRQ,
78  },
79  {
80  .start = -1, /* filled at runtime */
81  .flags = IORESOURCE_IRQ,
82  },
83 };
84 
85 static struct bcm63xx_enet_platform_data enet1_pd;
86 
87 static struct platform_device bcm63xx_enet1_device = {
88  .name = "bcm63xx_enet",
89  .id = 1,
90  .num_resources = ARRAY_SIZE(enet1_res),
91  .resource = enet1_res,
92  .dev = {
93  .platform_data = &enet1_pd,
94  },
95 };
96 
98  const struct bcm63xx_enet_platform_data *pd)
99 {
100  struct platform_device *pdev;
101  struct bcm63xx_enet_platform_data *dpd;
102  int ret;
103 
104  if (unit > 1)
105  return -ENODEV;
106 
107  if (unit == 1 && BCMCPU_IS_6338())
108  return -ENODEV;
109 
110  if (!shared_device_registered) {
111  shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
112  shared_res[0].end = shared_res[0].start;
113  if (BCMCPU_IS_6338())
114  shared_res[0].end += (RSET_ENETDMA_SIZE / 2) - 1;
115  else
116  shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
117 
118  ret = platform_device_register(&bcm63xx_enet_shared_device);
119  if (ret)
120  return ret;
121  shared_device_registered = 1;
122  }
123 
124  if (unit == 0) {
125  enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
126  enet0_res[0].end = enet0_res[0].start;
127  enet0_res[0].end += RSET_ENET_SIZE - 1;
128  enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0);
129  enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA);
130  enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA);
131  pdev = &bcm63xx_enet0_device;
132  } else {
133  enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1);
134  enet1_res[0].end = enet1_res[0].start;
135  enet1_res[0].end += RSET_ENET_SIZE - 1;
136  enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1);
137  enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA);
138  enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA);
139  pdev = &bcm63xx_enet1_device;
140  }
141 
142  /* copy given platform data */
143  dpd = pdev->dev.platform_data;
144  memcpy(dpd, pd, sizeof(*pd));
145 
146  /* adjust them in case internal phy is used */
147  if (dpd->use_internal_phy) {
148 
149  /* internal phy only exists for enet0 */
150  if (unit == 1)
151  return -ENODEV;
152 
153  dpd->phy_id = 1;
154  dpd->has_phy_interrupt = 1;
155  dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
156  }
157 
158  ret = platform_device_register(pdev);
159  if (ret)
160  return ret;
161  return 0;
162 }