1/*
2 * drivers/net/phy/at803x.c
3 *
4 * Driver for Atheros 803x PHY
5 *
6 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
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#include <linux/of_gpio.h>
20#include <linux/gpio/consumer.h>
21
22#define AT803X_INTR_ENABLE			0x12
23#define AT803X_INTR_STATUS			0x13
24#define AT803X_SMART_SPEED			0x14
25#define AT803X_LED_CONTROL			0x18
26#define AT803X_WOL_ENABLE			0x01
27#define AT803X_DEVICE_ADDR			0x03
28#define AT803X_LOC_MAC_ADDR_0_15_OFFSET		0x804C
29#define AT803X_LOC_MAC_ADDR_16_31_OFFSET	0x804B
30#define AT803X_LOC_MAC_ADDR_32_47_OFFSET	0x804A
31#define AT803X_MMD_ACCESS_CONTROL		0x0D
32#define AT803X_MMD_ACCESS_CONTROL_DATA		0x0E
33#define AT803X_FUNC_DATA			0x4003
34#define AT803X_INER				0x0012
35#define AT803X_INER_INIT			0xec00
36#define AT803X_INSR				0x0013
37#define AT803X_DEBUG_ADDR			0x1D
38#define AT803X_DEBUG_DATA			0x1E
39#define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
40#define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
41
42#define ATH8030_PHY_ID 0x004dd076
43#define ATH8031_PHY_ID 0x004dd074
44#define ATH8035_PHY_ID 0x004dd072
45
46MODULE_DESCRIPTION("Atheros 803x PHY driver");
47MODULE_AUTHOR("Matus Ujhelyi");
48MODULE_LICENSE("GPL");
49
50struct at803x_priv {
51	bool phy_reset:1;
52	struct gpio_desc *gpiod_reset;
53};
54
55struct at803x_context {
56	u16 bmcr;
57	u16 advertise;
58	u16 control1000;
59	u16 int_enable;
60	u16 smart_speed;
61	u16 led_control;
62};
63
64/* save relevant PHY registers to private copy */
65static void at803x_context_save(struct phy_device *phydev,
66				struct at803x_context *context)
67{
68	context->bmcr = phy_read(phydev, MII_BMCR);
69	context->advertise = phy_read(phydev, MII_ADVERTISE);
70	context->control1000 = phy_read(phydev, MII_CTRL1000);
71	context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
72	context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
73	context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
74}
75
76/* restore relevant PHY registers from private copy */
77static void at803x_context_restore(struct phy_device *phydev,
78				   const struct at803x_context *context)
79{
80	phy_write(phydev, MII_BMCR, context->bmcr);
81	phy_write(phydev, MII_ADVERTISE, context->advertise);
82	phy_write(phydev, MII_CTRL1000, context->control1000);
83	phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
84	phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
85	phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
86}
87
88static int at803x_set_wol(struct phy_device *phydev,
89			  struct ethtool_wolinfo *wol)
90{
91	struct net_device *ndev = phydev->attached_dev;
92	const u8 *mac;
93	int ret;
94	u32 value;
95	unsigned int i, offsets[] = {
96		AT803X_LOC_MAC_ADDR_32_47_OFFSET,
97		AT803X_LOC_MAC_ADDR_16_31_OFFSET,
98		AT803X_LOC_MAC_ADDR_0_15_OFFSET,
99	};
100
101	if (!ndev)
102		return -ENODEV;
103
104	if (wol->wolopts & WAKE_MAGIC) {
105		mac = (const u8 *) ndev->dev_addr;
106
107		if (!is_valid_ether_addr(mac))
108			return -EFAULT;
109
110		for (i = 0; i < 3; i++) {
111			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
112				  AT803X_DEVICE_ADDR);
113			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
114				  offsets[i]);
115			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
116				  AT803X_FUNC_DATA);
117			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
118				  mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
119		}
120
121		value = phy_read(phydev, AT803X_INTR_ENABLE);
122		value |= AT803X_WOL_ENABLE;
123		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
124		if (ret)
125			return ret;
126		value = phy_read(phydev, AT803X_INTR_STATUS);
127	} else {
128		value = phy_read(phydev, AT803X_INTR_ENABLE);
129		value &= (~AT803X_WOL_ENABLE);
130		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
131		if (ret)
132			return ret;
133		value = phy_read(phydev, AT803X_INTR_STATUS);
134	}
135
136	return ret;
137}
138
139static void at803x_get_wol(struct phy_device *phydev,
140			   struct ethtool_wolinfo *wol)
141{
142	u32 value;
143
144	wol->supported = WAKE_MAGIC;
145	wol->wolopts = 0;
146
147	value = phy_read(phydev, AT803X_INTR_ENABLE);
148	if (value & AT803X_WOL_ENABLE)
149		wol->wolopts |= WAKE_MAGIC;
150}
151
152static int at803x_suspend(struct phy_device *phydev)
153{
154	int value;
155	int wol_enabled;
156
157	mutex_lock(&phydev->lock);
158
159	value = phy_read(phydev, AT803X_INTR_ENABLE);
160	wol_enabled = value & AT803X_WOL_ENABLE;
161
162	value = phy_read(phydev, MII_BMCR);
163
164	if (wol_enabled)
165		value |= BMCR_ISOLATE;
166	else
167		value |= BMCR_PDOWN;
168
169	phy_write(phydev, MII_BMCR, value);
170
171	mutex_unlock(&phydev->lock);
172
173	return 0;
174}
175
176static int at803x_resume(struct phy_device *phydev)
177{
178	int value;
179
180	mutex_lock(&phydev->lock);
181
182	value = phy_read(phydev, MII_BMCR);
183	value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
184	phy_write(phydev, MII_BMCR, value);
185
186	mutex_unlock(&phydev->lock);
187
188	return 0;
189}
190
191static int at803x_probe(struct phy_device *phydev)
192{
193	struct device *dev = &phydev->dev;
194	struct at803x_priv *priv;
195	struct gpio_desc *gpiod_reset;
196
197	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
198	if (!priv)
199		return -ENOMEM;
200
201	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
202	if (IS_ERR(gpiod_reset))
203		return PTR_ERR(gpiod_reset);
204
205	priv->gpiod_reset = gpiod_reset;
206
207	phydev->priv = priv;
208
209	return 0;
210}
211
212static int at803x_config_init(struct phy_device *phydev)
213{
214	int ret;
215
216	ret = genphy_config_init(phydev);
217	if (ret < 0)
218		return ret;
219
220	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
221		ret = phy_write(phydev, AT803X_DEBUG_ADDR,
222				AT803X_DEBUG_SYSTEM_MODE_CTRL);
223		if (ret)
224			return ret;
225		ret = phy_write(phydev, AT803X_DEBUG_DATA,
226				AT803X_DEBUG_RGMII_TX_CLK_DLY);
227		if (ret)
228			return ret;
229	}
230
231	return 0;
232}
233
234static int at803x_ack_interrupt(struct phy_device *phydev)
235{
236	int err;
237
238	err = phy_read(phydev, AT803X_INSR);
239
240	return (err < 0) ? err : 0;
241}
242
243static int at803x_config_intr(struct phy_device *phydev)
244{
245	int err;
246	int value;
247
248	value = phy_read(phydev, AT803X_INER);
249
250	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
251		err = phy_write(phydev, AT803X_INER,
252				value | AT803X_INER_INIT);
253	else
254		err = phy_write(phydev, AT803X_INER, 0);
255
256	return err;
257}
258
259static void at803x_link_change_notify(struct phy_device *phydev)
260{
261	struct at803x_priv *priv = phydev->priv;
262
263	/*
264	 * Conduct a hardware reset for AT8030 every time a link loss is
265	 * signalled. This is necessary to circumvent a hardware bug that
266	 * occurs when the cable is unplugged while TX packets are pending
267	 * in the FIFO. In such cases, the FIFO enters an error mode it
268	 * cannot recover from by software.
269	 */
270	if (phydev->drv->phy_id == ATH8030_PHY_ID) {
271		if (phydev->state == PHY_NOLINK) {
272			if (priv->gpiod_reset && !priv->phy_reset) {
273				struct at803x_context context;
274
275				at803x_context_save(phydev, &context);
276
277				gpiod_set_value(priv->gpiod_reset, 0);
278				msleep(1);
279				gpiod_set_value(priv->gpiod_reset, 1);
280				msleep(1);
281
282				at803x_context_restore(phydev, &context);
283
284				dev_dbg(&phydev->dev, "%s(): phy was reset\n",
285					__func__);
286				priv->phy_reset = true;
287			}
288		} else {
289			priv->phy_reset = false;
290		}
291	}
292}
293
294static struct phy_driver at803x_driver[] = {
295{
296	/* ATHEROS 8035 */
297	.phy_id			= ATH8035_PHY_ID,
298	.name			= "Atheros 8035 ethernet",
299	.phy_id_mask		= 0xffffffef,
300	.probe			= at803x_probe,
301	.config_init		= at803x_config_init,
302	.link_change_notify	= at803x_link_change_notify,
303	.set_wol		= at803x_set_wol,
304	.get_wol		= at803x_get_wol,
305	.suspend		= at803x_suspend,
306	.resume			= at803x_resume,
307	.features		= PHY_GBIT_FEATURES,
308	.flags			= PHY_HAS_INTERRUPT,
309	.config_aneg		= genphy_config_aneg,
310	.read_status		= genphy_read_status,
311	.driver			= {
312		.owner = THIS_MODULE,
313	},
314}, {
315	/* ATHEROS 8030 */
316	.phy_id			= ATH8030_PHY_ID,
317	.name			= "Atheros 8030 ethernet",
318	.phy_id_mask		= 0xffffffef,
319	.probe			= at803x_probe,
320	.config_init		= at803x_config_init,
321	.link_change_notify	= at803x_link_change_notify,
322	.set_wol		= at803x_set_wol,
323	.get_wol		= at803x_get_wol,
324	.suspend		= at803x_suspend,
325	.resume			= at803x_resume,
326	.features		= PHY_GBIT_FEATURES,
327	.flags			= PHY_HAS_INTERRUPT,
328	.config_aneg		= genphy_config_aneg,
329	.read_status		= genphy_read_status,
330	.driver			= {
331		.owner = THIS_MODULE,
332	},
333}, {
334	/* ATHEROS 8031 */
335	.phy_id			= ATH8031_PHY_ID,
336	.name			= "Atheros 8031 ethernet",
337	.phy_id_mask		= 0xffffffef,
338	.probe			= at803x_probe,
339	.config_init		= at803x_config_init,
340	.link_change_notify	= at803x_link_change_notify,
341	.set_wol		= at803x_set_wol,
342	.get_wol		= at803x_get_wol,
343	.suspend		= at803x_suspend,
344	.resume			= at803x_resume,
345	.features		= PHY_GBIT_FEATURES,
346	.flags			= PHY_HAS_INTERRUPT,
347	.config_aneg		= genphy_config_aneg,
348	.read_status		= genphy_read_status,
349	.ack_interrupt		= &at803x_ack_interrupt,
350	.config_intr		= &at803x_config_intr,
351	.driver			= {
352		.owner = THIS_MODULE,
353	},
354} };
355
356module_phy_driver(at803x_driver);
357
358static struct mdio_device_id __maybe_unused atheros_tbl[] = {
359	{ ATH8030_PHY_ID, 0xffffffef },
360	{ ATH8031_PHY_ID, 0xffffffef },
361	{ ATH8035_PHY_ID, 0xffffffef },
362	{ }
363};
364
365MODULE_DEVICE_TABLE(mdio, atheros_tbl);
366