1/*
2 * ar80xx.c: ar80xx(ar8031/ar8033/ar8035) PHY driver
3 *
4 * Copyright (c) 2013 The Linux Foundation. All rights reserved.
5 * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
6 * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/if.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/list.h>
23#include <linux/if_ether.h>
24#include <linux/skbuff.h>
25#include <linux/netdevice.h>
26#include <linux/netlink.h>
27#include <linux/bitops.h>
28#include <net/genetlink.h>
29#include <linux/delay.h>
30#include <linux/phy.h>
31#include <linux/netdevice.h>
32#include <linux/etherdevice.h>
33#include <linux/lockdep.h>
34#include "ar80xx.h"
35#include <asm/mach-ath79/ar71xx_regs.h>
36
37static int
38ar8033_config_init(struct phy_device *pdev)
39{
40	u32 v;
41	v = phy_read(pdev, AR80XX_REG_CHIP_CONFIG);
42	phy_write(pdev, AR80XX_REG_CHIP_CONFIG, AR80XX_BT_BX_REG_SEL | v);
43
44	pdev->autoneg = AUTONEG_ENABLE;
45
46	return 0;
47}
48
49static int
50ar8033_read_status(struct phy_device *pdev)
51{
52	void __iomem *base;
53
54	genphy_read_status(pdev);
55
56	base = ioremap(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
57
58	if (pdev->speed == SPEED_1000) {
59		__raw_writel( ETH_SGMII_GIGE_SET(1) | ETH_SGMII_CLK_SEL_SET(1),
60			base + ETH_SGMII_ADDRESS_OFFSET);
61	} else if (pdev->speed == SPEED_100) {
62		__raw_writel( ETH_SGMII_PHASE0_COUNT_SET(1) | ETH_SGMII_PHASE1_COUNT_SET(1),
63			base + ETH_SGMII_ADDRESS_OFFSET);
64	} else {
65		__raw_writel( ETH_SGMII_PHASE0_COUNT_SET(19) | ETH_SGMII_PHASE1_COUNT_SET(19),
66			base + ETH_SGMII_ADDRESS_OFFSET);
67	}
68	iounmap(base);
69
70	return 0;
71}
72
73static int
74ar8033_config_aneg(struct phy_device *pdev)
75{
76	u32 v;
77
78	v = phy_read(pdev, MII_BMCR);
79	phy_write(pdev, MII_BMCR, v | AR80XX_AUTO_NEGO);
80
81	v = genphy_config_aneg(pdev);
82	if (v < 0) {
83		printk("%s, Error: 0x%x\n", __func__, v);
84		return v;
85	}
86
87	return 0;
88}
89
90static int
91ar8033_probe(struct phy_device *pdev)
92{
93	return 0;
94}
95
96static void
97ar8033_remove(struct phy_device *pdev)
98{
99}
100
101static struct phy_driver ar80xx_phy_drivers[] = {
102    {
103	.phy_id		= AR80XX_PHY_ID_AR8033,
104	.name		= "Qualcomm Atheros AR8033 PHY",
105	.phy_id_mask	= AR80XX_PHY_ID_MASK,
106	.features	= PHY_GBIT_FEATURES,
107	.probe          = ar8033_probe,
108	.remove         = ar8033_remove,
109	.config_init	= &ar8033_config_init,
110	.config_aneg	= &ar8033_config_aneg,
111	.read_status    = &ar8033_read_status,
112	.driver		= { .owner = THIS_MODULE },
113    },
114};
115
116int __init
117ar80xx_phy_init(void)
118{
119	int ret;
120	int i;
121
122	for (i = 0; i < ARRAY_SIZE(ar80xx_phy_drivers); i++) {
123		ret = phy_driver_register(&ar80xx_phy_drivers[i]);
124		if (ret) {
125			while (i-- > 0)
126				phy_driver_unregister(&ar80xx_phy_drivers[i]);
127			return ret;
128		}
129	}
130	return 0;
131}
132
133void __exit
134ar80xx_phy_exit(void)
135{
136	int i;
137
138	for (i = 0; i < ARRAY_SIZE(ar80xx_phy_drivers); i++)
139		phy_driver_unregister(&ar80xx_phy_drivers[i]);
140}
141
142module_init(ar80xx_phy_init);
143module_exit(ar80xx_phy_exit);
144MODULE_LICENSE("GPL");
145
146