Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
at803x.c
Go to the documentation of this file.
1 /*
2  * drivers/net/phy/at803x.c
3  *
4  * Driver for Atheros 803x PHY
5  *
6  * Author: Matus Ujhelyi <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2 of the License, or (at your
11  * option) any later version.
12  */
13 
14 #include <linux/phy.h>
15 #include <linux/module.h>
16 #include <linux/string.h>
17 #include <linux/netdevice.h>
18 #include <linux/etherdevice.h>
19 
20 #define AT803X_INTR_ENABLE 0x12
21 #define AT803X_INTR_STATUS 0x13
22 #define AT803X_WOL_ENABLE 0x01
23 #define AT803X_DEVICE_ADDR 0x03
24 #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
25 #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
26 #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
27 #define AT803X_MMD_ACCESS_CONTROL 0x0D
28 #define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
29 #define AT803X_FUNC_DATA 0x4003
30 
31 MODULE_DESCRIPTION("Atheros 803x PHY driver");
32 MODULE_AUTHOR("Matus Ujhelyi");
33 MODULE_LICENSE("GPL");
34 
35 static void at803x_set_wol_mac_addr(struct phy_device *phydev)
36 {
37  struct net_device *ndev = phydev->attached_dev;
38  const u8 *mac;
39  unsigned int i, offsets[] = {
43  };
44 
45  if (!ndev)
46  return;
47 
48  mac = (const u8 *) ndev->dev_addr;
49 
50  if (!is_valid_ether_addr(mac))
51  return;
52 
53  for (i = 0; i < 3; i++) {
57  offsets[i]);
61  mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
62  }
63 }
64 
65 static int at803x_config_init(struct phy_device *phydev)
66 {
67  int val;
68  u32 features;
69  int status;
70 
73 
74  val = phy_read(phydev, MII_BMSR);
75  if (val < 0)
76  return val;
77 
78  if (val & BMSR_ANEGCAPABLE)
79  features |= SUPPORTED_Autoneg;
80  if (val & BMSR_100FULL)
81  features |= SUPPORTED_100baseT_Full;
82  if (val & BMSR_100HALF)
83  features |= SUPPORTED_100baseT_Half;
84  if (val & BMSR_10FULL)
85  features |= SUPPORTED_10baseT_Full;
86  if (val & BMSR_10HALF)
87  features |= SUPPORTED_10baseT_Half;
88 
89  if (val & BMSR_ESTATEN) {
90  val = phy_read(phydev, MII_ESTATUS);
91  if (val < 0)
92  return val;
93 
94  if (val & ESTATUS_1000_TFULL)
95  features |= SUPPORTED_1000baseT_Full;
96  if (val & ESTATUS_1000_THALF)
97  features |= SUPPORTED_1000baseT_Half;
98  }
99 
100  phydev->supported = features;
101  phydev->advertising = features;
102 
103  /* enable WOL */
104  at803x_set_wol_mac_addr(phydev);
106  status = phy_read(phydev, AT803X_INTR_STATUS);
107 
108  return 0;
109 }
110 
111 /* ATHEROS 8035 */
112 static struct phy_driver at8035_driver = {
113  .phy_id = 0x004dd072,
114  .name = "Atheros 8035 ethernet",
115  .phy_id_mask = 0xffffffef,
116  .config_init = at803x_config_init,
117  .features = PHY_GBIT_FEATURES,
118  .flags = PHY_HAS_INTERRUPT,
119  .config_aneg = &genphy_config_aneg,
120  .read_status = &genphy_read_status,
121  .driver = {
122  .owner = THIS_MODULE,
123  },
124 };
125 
126 /* ATHEROS 8030 */
127 static struct phy_driver at8030_driver = {
128  .phy_id = 0x004dd076,
129  .name = "Atheros 8030 ethernet",
130  .phy_id_mask = 0xffffffef,
131  .config_init = at803x_config_init,
132  .features = PHY_GBIT_FEATURES,
133  .flags = PHY_HAS_INTERRUPT,
134  .config_aneg = &genphy_config_aneg,
135  .read_status = &genphy_read_status,
136  .driver = {
137  .owner = THIS_MODULE,
138  },
139 };
140 
141 static int __init atheros_init(void)
142 {
143  int ret;
144 
145  ret = phy_driver_register(&at8035_driver);
146  if (ret)
147  goto err1;
148 
149  ret = phy_driver_register(&at8030_driver);
150  if (ret)
151  goto err2;
152 
153  return 0;
154 
155 err2:
156  phy_driver_unregister(&at8035_driver);
157 err1:
158  return ret;
159 }
160 
161 static void __exit atheros_exit(void)
162 {
163  phy_driver_unregister(&at8035_driver);
164  phy_driver_unregister(&at8030_driver);
165 }
166 
167 module_init(atheros_init);
168 module_exit(atheros_exit);
169 
170 static struct mdio_device_id __maybe_unused atheros_tbl[] = {
171  { 0x004dd076, 0xffffffef },
172  { 0x004dd072, 0xffffffef },
173  { }
174 };
175 
176 MODULE_DEVICE_TABLE(mdio, atheros_tbl);