icplus.c (f7e290fbeb336421ba6237548b693c9afb4d75fa) icplus.c (f2f1a847e74f61fb151e0f6f689a8485345ed1fc)
1/*
2 * Driver for ICPlus PHYs
3 *
4 * Copyright (c) 2007 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your

--- 11 unchanged lines hidden (view full) ---

20#include <linux/etherdevice.h>
21#include <linux/skbuff.h>
22#include <linux/spinlock.h>
23#include <linux/mm.h>
24#include <linux/module.h>
25#include <linux/mii.h>
26#include <linux/ethtool.h>
27#include <linux/phy.h>
1/*
2 * Driver for ICPlus PHYs
3 *
4 * Copyright (c) 2007 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your

--- 11 unchanged lines hidden (view full) ---

20#include <linux/etherdevice.h>
21#include <linux/skbuff.h>
22#include <linux/spinlock.h>
23#include <linux/mm.h>
24#include <linux/module.h>
25#include <linux/mii.h>
26#include <linux/ethtool.h>
27#include <linux/phy.h>
28#include <linux/property.h>
28
29#include <asm/io.h>
30#include <asm/irq.h>
31#include <linux/uaccess.h>
32
33MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
34MODULE_AUTHOR("Michael Barkowski");
35MODULE_LICENSE("GPL");

--- 7 unchanged lines hidden (view full) ---

43#define IP101A_G_APS_ON BIT(1) /* IP101A/G APS Mode bit */
44#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */
45#define IP101A_G_IRQ_PIN_USED BIT(15) /* INTR pin used */
46#define IP101A_G_IRQ_ALL_MASK BIT(11) /* IRQ's inactive */
47#define IP101A_G_IRQ_SPEED_CHANGE BIT(2)
48#define IP101A_G_IRQ_DUPLEX_CHANGE BIT(1)
49#define IP101A_G_IRQ_LINK_CHANGE BIT(0)
50
29
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <linux/uaccess.h>
33
34MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
35MODULE_AUTHOR("Michael Barkowski");
36MODULE_LICENSE("GPL");

--- 7 unchanged lines hidden (view full) ---

44#define IP101A_G_APS_ON BIT(1) /* IP101A/G APS Mode bit */
45#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */
46#define IP101A_G_IRQ_PIN_USED BIT(15) /* INTR pin used */
47#define IP101A_G_IRQ_ALL_MASK BIT(11) /* IRQ's inactive */
48#define IP101A_G_IRQ_SPEED_CHANGE BIT(2)
49#define IP101A_G_IRQ_DUPLEX_CHANGE BIT(1)
50#define IP101A_G_IRQ_LINK_CHANGE BIT(0)
51
52#define IP101G_DIGITAL_IO_SPEC_CTRL 0x1d
53#define IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32 BIT(2)
54
55/* The 32-pin IP101GR package can re-configure the mode of the RXER/INTR_32 pin
56 * (pin number 21). The hardware default is RXER (receive error) mode. But it
57 * can be configured to interrupt mode manually.
58 */
59enum ip101gr_sel_intr32 {
60 IP101GR_SEL_INTR32_KEEP,
61 IP101GR_SEL_INTR32_INTR,
62 IP101GR_SEL_INTR32_RXER,
63};
64
65struct ip101a_g_phy_priv {
66 enum ip101gr_sel_intr32 sel_intr32;
67};
68
51static int ip175c_config_init(struct phy_device *phydev)
52{
53 int err, i;
54 static int full_reset_performed;
55
56 if (full_reset_performed == 0) {
57
58 /* master reset */

--- 120 unchanged lines hidden (view full) ---

179static int ip175c_config_aneg(struct phy_device *phydev)
180{
181 if (phydev->mdio.addr == 4) /* WAN port */
182 genphy_config_aneg(phydev);
183
184 return 0;
185}
186
69static int ip175c_config_init(struct phy_device *phydev)
70{
71 int err, i;
72 static int full_reset_performed;
73
74 if (full_reset_performed == 0) {
75
76 /* master reset */

--- 120 unchanged lines hidden (view full) ---

197static int ip175c_config_aneg(struct phy_device *phydev)
198{
199 if (phydev->mdio.addr == 4) /* WAN port */
200 genphy_config_aneg(phydev);
201
202 return 0;
203}
204
205static int ip101a_g_probe(struct phy_device *phydev)
206{
207 struct device *dev = &phydev->mdio.dev;
208 struct ip101a_g_phy_priv *priv;
209
210 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
211 if (!priv)
212 return -ENOMEM;
213
214 /* Both functions (RX error and interrupt status) are sharing the same
215 * pin on the 32-pin IP101GR, so this is an exclusive choice.
216 */
217 if (device_property_read_bool(dev, "icplus,select-rx-error") &&
218 device_property_read_bool(dev, "icplus,select-interrupt")) {
219 dev_err(dev,
220 "RXER and INTR mode cannot be selected together\n");
221 return -EINVAL;
222 }
223
224 if (device_property_read_bool(dev, "icplus,select-rx-error"))
225 priv->sel_intr32 = IP101GR_SEL_INTR32_RXER;
226 else if (device_property_read_bool(dev, "icplus,select-interrupt"))
227 priv->sel_intr32 = IP101GR_SEL_INTR32_INTR;
228 else
229 priv->sel_intr32 = IP101GR_SEL_INTR32_KEEP;
230
231 phydev->priv = priv;
232
233 return 0;
234}
235
187static int ip101a_g_config_init(struct phy_device *phydev)
188{
236static int ip101a_g_config_init(struct phy_device *phydev)
237{
189 int c;
238 struct ip101a_g_phy_priv *priv = phydev->priv;
239 int err, c;
190
191 c = ip1xx_reset(phydev);
192 if (c < 0)
193 return c;
194
240
241 c = ip1xx_reset(phydev);
242 if (c < 0)
243 return c;
244
245 /* configure the RXER/INTR_32 pin of the 32-pin IP101GR if needed: */
246 switch (priv->sel_intr32) {
247 case IP101GR_SEL_INTR32_RXER:
248 err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
249 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32, 0);
250 if (err < 0)
251 return err;
252 break;
253
254 case IP101GR_SEL_INTR32_INTR:
255 err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
256 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32,
257 IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32);
258 if (err < 0)
259 return err;
260 break;
261
262 default:
263 /* Don't touch IP101G_DIGITAL_IO_SPEC_CTRL because it's not
264 * documented on IP101A and it's not clear whether this would
265 * cause problems.
266 * For the 32-pin IP101GR we simply keep the SEL_INTR32
267 * configuration as set by the bootloader when not configured
268 * to one of the special functions.
269 */
270 break;
271 }
272
195 /* Enable Auto Power Saving mode */
196 c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
197 c |= IP101A_G_APS_ON;
198
199 return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
200}
201
202static int ip101a_g_config_intr(struct phy_device *phydev)

--- 49 unchanged lines hidden (view full) ---

252 .config_init = &ip1001_config_init,
253 .suspend = genphy_suspend,
254 .resume = genphy_resume,
255}, {
256 .phy_id = 0x02430c54,
257 .name = "ICPlus IP101A/G",
258 .phy_id_mask = 0x0ffffff0,
259 .features = PHY_BASIC_FEATURES,
273 /* Enable Auto Power Saving mode */
274 c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
275 c |= IP101A_G_APS_ON;
276
277 return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
278}
279
280static int ip101a_g_config_intr(struct phy_device *phydev)

--- 49 unchanged lines hidden (view full) ---

330 .config_init = &ip1001_config_init,
331 .suspend = genphy_suspend,
332 .resume = genphy_resume,
333}, {
334 .phy_id = 0x02430c54,
335 .name = "ICPlus IP101A/G",
336 .phy_id_mask = 0x0ffffff0,
337 .features = PHY_BASIC_FEATURES,
338 .probe = ip101a_g_probe,
260 .config_intr = ip101a_g_config_intr,
261 .did_interrupt = ip101a_g_did_interrupt,
262 .ack_interrupt = ip101a_g_ack_interrupt,
263 .config_init = &ip101a_g_config_init,
264 .suspend = genphy_suspend,
265 .resume = genphy_resume,
266} };
267
268module_phy_driver(icplus_driver);
269
270static struct mdio_device_id __maybe_unused icplus_tbl[] = {
271 { 0x02430d80, 0x0ffffff0 },
272 { 0x02430d90, 0x0ffffff0 },
273 { 0x02430c54, 0x0ffffff0 },
274 { }
275};
276
277MODULE_DEVICE_TABLE(mdio, icplus_tbl);
339 .config_intr = ip101a_g_config_intr,
340 .did_interrupt = ip101a_g_did_interrupt,
341 .ack_interrupt = ip101a_g_ack_interrupt,
342 .config_init = &ip101a_g_config_init,
343 .suspend = genphy_suspend,
344 .resume = genphy_resume,
345} };
346
347module_phy_driver(icplus_driver);
348
349static struct mdio_device_id __maybe_unused icplus_tbl[] = {
350 { 0x02430d80, 0x0ffffff0 },
351 { 0x02430d90, 0x0ffffff0 },
352 { 0x02430c54, 0x0ffffff0 },
353 { }
354};
355
356MODULE_DEVICE_TABLE(mdio, icplus_tbl);